11 KiB
weatherfeeder API (Wire Contract)
This document defines the stable, consumer-facing JSON contract emitted by weatherfeeder sinks.
weatherfeeder emits events encoded as JSON. Each event has:
- an envelope (metadata + schema identifier), and
- a payload whose shape is determined by
schema.
Downstream consumers should:
- parse the event envelope,
- switch on
schema, then - decode
payloadinto the matching schema.
Event envelope
All events are JSON objects with these fields:
| Field | Type | Required | Notes |
|---|---|---|---|
id |
string | yes | Stable event identifier. Treat as opaque. |
schema |
string | yes | Schema identifier (e.g. weather.observation.v1). |
source |
string | yes | Provider/source identifier (stable within configuration). |
effectiveAt |
string (timestamp) | yes | RFC3339Nano timestamp indicating when this event is effective. |
payload |
object | yes | Schema-specific payload (see below). |
Timestamp format
All timestamps are encoded as JSON strings using Go’s time.Time JSON encoding (RFC3339Nano).
Examples:
"2026-01-17T14:27:00Z""2026-01-17T08:27:00-06:00"
Canonical schemas
weatherfeeder emits three canonical domain schemas:
weather.observation.v1weather.forecast.v1weather.alert.v1
Each payload is described below using the JSON field names as the contract.
Shared conventions
Optional fields
Most non-identity measurements are optional. Optional fields are omitted when unknown (i.e., not present).
Units
Canonical payloads are normalized to metric units:
- Temperature:
*C(Celsius) - Wind speed/gust:
*Kmh(kilometers/hour) - Pressure:
*Pa(Pascals) - Visibility / distance / elevation:
*Meters(meters) - Precipitation amount / snowfall depth:
*Mm(millimeters) - Humidity / cloud cover / PoP:
*Percent(0–100)
Float rounding
For readability and stability, weatherfeeder rounds floating-point values in canonical payloads to 2 digits after the decimal during normalization finalization.
WMO condition codes
conditionCode uses the WMO weather interpretation code vocabulary.
- Type: integer
- Unknown/unmappable:
-1
Downstream consumers should treat unknown codes as “unknown conditions” rather than failing decoding.
Schema: weather.observation.v1
Payload type: WeatherObservation
A WeatherObservation represents a point-in-time observation for a station/location.
Fields
| Field | Type | Required | Units / Notes |
|---|---|---|---|
stationId |
string | no | Provider station/location identifier |
stationName |
string | no | Human name, if available |
timestamp |
string (timestamp) | yes | Observation time |
conditionCode |
int | yes | WMO code (-1 for unknown) |
conditionText |
string | no | Canonical short text (often derived from WMO code) |
isDay |
bool | no | Day/night hint when available |
providerRawDescription |
string | no | Provider-specific “evidence” text |
textDescription |
string | no | Legacy/transitional human text |
iconUrl |
string | no | Legacy/transitional icon URL |
temperatureC |
number | no | °C |
dewpointC |
number | no | °C |
windDirectionDegrees |
number | no | Degrees (meteorological) |
windSpeedKmh |
number | no | km/h |
windGustKmh |
number | no | km/h |
barometricPressurePa |
number | no | Pa |
seaLevelPressurePa |
number | no | Pa |
visibilityMeters |
number | no | meters |
relativeHumidityPercent |
number | no | percent (0–100) |
apparentTemperatureC |
number | no | °C |
elevationMeters |
number | no | meters |
rawMessage |
string | no | Provider raw message (e.g. METAR), if available |
presentWeather |
array | no | Provider-specific structured fragments |
cloudLayers |
array | no | Cloud layers (base + amount) |
Nested: cloudLayers[]
Each cloudLayers[] element:
| Field | Type | Required | Notes |
|---|---|---|---|
baseMeters |
number | no | Cloud base altitude in meters |
amount |
string | no | Provider string (e.g. FEW/SCT/BKN/OVC) |
Nested: presentWeather[]
Each presentWeather[] element:
| Field | Type | Required | Notes |
|---|---|---|---|
raw |
object | no | Provider-specific JSON object |
Schema: weather.forecast.v1
Payload type: WeatherForecastRun
A WeatherForecastRun is a single issued forecast snapshot for a location and a specific product
(hourly / narrative / daily). The run contains an ordered list of forecast periods.
product values
product is one of:
"hourly""narrative""daily"
Fields
| Field | Type | Required | Notes |
|---|---|---|---|
locationId |
string | no | Provider location identifier |
locationName |
string | no | Human name, if available |
issuedAt |
string (timestamp) | yes | When this run was generated/issued |
updatedAt |
string (timestamp) | no | Optional later update time |
product |
string | yes | "hourly", "narrative", or "daily" |
latitude |
number | no | Degrees |
longitude |
number | no | Degrees |
elevationMeters |
number | no | meters |
periods |
array | yes | Chronological forecast periods |
Nested: periods[] (WeatherForecastPeriod)
A WeatherForecastPeriod is valid for [startTime, endTime).
| Field | Type | Required | Units / Notes |
|---|---|---|---|
startTime |
string (timestamp) | yes | Period start |
endTime |
string (timestamp) | yes | Period end |
name |
string | no | Human label (often empty for hourly) |
isDay |
bool | no | Day/night hint |
conditionCode |
int | yes | WMO code (-1 for unknown) |
conditionText |
string | no | Canonical short text |
providerRawDescription |
string | no | Provider-specific “evidence” text |
textDescription |
string | no | Human-facing short phrase |
detailedText |
string | no | Longer narrative |
iconUrl |
string | no | Legacy/transitional |
temperatureC |
number | no | °C |
temperatureCMin |
number | no | °C (aggregated products) |
temperatureCMax |
number | no | °C (aggregated products) |
dewpointC |
number | no | °C |
relativeHumidityPercent |
number | no | percent |
windDirectionDegrees |
number | no | degrees |
windSpeedKmh |
number | no | km/h |
windGustKmh |
number | no | km/h |
barometricPressurePa |
number | no | Pa |
visibilityMeters |
number | no | meters |
apparentTemperatureC |
number | no | °C |
cloudCoverPercent |
number | no | percent |
probabilityOfPrecipitationPercent |
number | no | percent |
precipitationAmountMm |
number | no | mm (liquid equivalent) |
snowfallDepthMm |
number | no | mm |
uvIndex |
number | no | unitless index |
Schema: weather.alert.v1
Payload type: WeatherAlertRun
A WeatherAlertRun is a snapshot of active alerts for a location as-of a point in time.
A run may contain zero, one, or many alerts.
Fields
| Field | Type | Required | Notes |
|---|---|---|---|
locationId |
string | no | Provider location identifier |
locationName |
string | no | Human name, if available |
asOf |
string (timestamp) | yes | When the provider asserted this snapshot is current |
latitude |
number | no | Degrees |
longitude |
number | no | Degrees |
alerts |
array | yes | Active alerts (order provider-dependent) |
Nested: alerts[] (WeatherAlert)
| Field | Type | Required | Notes |
|---|---|---|---|
id |
string | yes | Provider-stable identifier (often a URL/URI) |
event |
string | no | Classification |
headline |
string | no | Short headline |
severity |
string | no | e.g. Extreme/Severe/Moderate/Minor/Unknown |
urgency |
string | no | e.g. Immediate/Expected/Future/Past/Unknown |
certainty |
string | no | e.g. Observed/Likely/Possible/Unlikely/Unknown |
status |
string | no | e.g. Actual/Exercise/Test/System/Unknown |
messageType |
string | no | e.g. Alert/Update/Cancel |
category |
string | no | e.g. Met/Geo/Safety/... |
response |
string | no | e.g. Shelter/Evacuate/Prepare/... |
description |
string | no | Narrative |
instruction |
string | no | What to do |
sent |
string (timestamp) | no | Provider-dependent |
effective |
string (timestamp) | no | Provider-dependent |
onset |
string (timestamp) | no | Provider-dependent |
expires |
string (timestamp) | no | Provider-dependent |
areaDescription |
string | no | Often a provider string |
senderName |
string | no | Provenance |
references |
array | no | Related alert references |
Nested: references[] (AlertReference)
| Field | Type | Required | Notes |
|---|---|---|---|
id |
string | no | Provider reference ID/URI |
identifier |
string | no | Provider identifier string, if distinct |
sender |
string | no | Sender |
sent |
string (timestamp) | no | Timestamp |
Compatibility rules
- Consumers must ignore unknown fields.
- Producers (weatherfeeder) prefer additive changes within a schema version.
- Renames/removals/semantic breaks require a schema version bump (
weather.*.v2).
Examples
Observation event (weather.observation.v1)
{
"id": "nws:KSTL:2026-01-17T14:00:00Z",
"schema": "weather.observation.v1",
"source": "nws_observation",
"effectiveAt": "2026-01-17T14:00:00Z",
"payload": {
"stationId": "KSTL",
"timestamp": "2026-01-17T14:00:00Z",
"conditionCode": 1,
"conditionText": "Mainly Sunny",
"temperatureC": 3.25,
"windSpeedKmh": 18.5
}
}
Forecast event (weather.forecast.v1)
{
"id": "openmeteo:38.63,-90.20:2026-01-17T13:00:00Z",
"schema": "weather.forecast.v1",
"source": "openmeteo_forecast",
"effectiveAt": "2026-01-17T13:00:00Z",
"payload": {
"locationName": "St. Louis, MO",
"issuedAt": "2026-01-17T13:00:00Z",
"product": "hourly",
"latitude": 38.63,
"longitude": -90.2,
"periods": [
{
"startTime": "2026-01-17T14:00:00Z",
"endTime": "2026-01-17T15:00:00Z",
"conditionCode": 2,
"conditionText": "Partly Cloudy",
"temperatureC": 3.5,
"probabilityOfPrecipitationPercent": 10
}
]
}
}
Alert event (weather.alert.v1)
{
"id": "nws:alerts:2026-01-17T14:10:00Z",
"schema": "weather.alert.v1",
"source": "nws_alerts",
"effectiveAt": "2026-01-17T14:10:00Z",
"payload": {
"asOf": "2026-01-17T14:05:00Z",
"alerts": [
{
"id": "https://api.weather.gov/alerts/abc123",
"event": "Winter Weather Advisory",
"headline": "Winter Weather Advisory issued January 17 at 8:05AM CST",
"severity": "Moderate",
"description": "Mixed precipitation expected...",
"expires": "2026-01-18T06:00:00Z"
}
]
}
}