16 KiB
weatherapi HTTP API
This is the canonical public HTTP contract for weatherapi. The service is a
read-only API over the latest weather records available in the configured
weatherfeeder-populated Postgres database.
Base URL
All paths are relative to the deployment root:
http://localhost:8080
Use your deployment host in production.
Authentication
weatherapi does not implement authentication or authorization. Put access
control in front of the service when a deployment requires it.
Response Envelope
Successful JSON and XML responses use a top-level envelope:
{
"data": {}
}
When no latest/current resource exists, the request still succeeds and returns
data: null.
Text responses are rendered from endpoint-specific templates. When the payload is missing, the templates return a short no-data message.
Formats
Every implemented endpoint can produce:
| Format | Media type |
|---|---|
json |
application/json |
xml |
application/xml |
text |
text/plain |
Format selection is:
formatquery parameter;Acceptheader;- configured
server.default_format.
format values are case-insensitive. Unsupported formats return 406 Not Acceptable with an error envelope.
Shared Query Rules
Unknown query parameters are rejected with 400 Bad Request.
| Parameter | Values | Default | Supported on |
|---|---|---|---|
format |
json, xml, text |
configured default | all endpoints |
units |
metric, us |
metric |
all endpoints |
precision |
integer 0 through 2 |
0 |
observations, current conditions, forecasts |
tz or TZ |
timezone selector | UTC/no conversion | forecasts, discussions, weather stories, outlooks |
units, format, and precision values are normalized case-insensitively
where applicable. units=metric returns metric field names; units=us returns
US-customary field names for unit-bearing payloads. Alerts, discussions, and
weather stories accept units but their current payload fields are not
materially changed by it. Outlooks also accept units without changing payload
values or field names.
precision controls numeric rounding. The default 0 rounds to whole numbers.
precision is rejected on alerts, discussions, weather stories, and outlooks.
Timezone selectors accepted by tz / TZ:
- IANA timezone names such as
America/Chicago; - common US abbreviations such as
CDT,CST,EDT,EST,MDT,MST,PDT, andPST; - UTC offsets in
+H,+HH,+HH:MM,-H,-HH, or-HH:MMform, bounded to-14:00through+14:00; - aliases
ChicagoandStl, both mapped toAmerica/Chicago.
If both tz and TZ are provided, their values must match
case-insensitively. Timezone conversion affects rendered timestamps and forecast
/today and /tomorrow day-slice filtering. Without a timezone parameter,
day-slice routes use UTC.
Errors
API errors use a stable error envelope:
{
"error": {
"code": "invalid_parameter",
"message": "..."
}
}
Implemented API error statuses:
| Status | Code | Cause |
|---|---|---|
400 Bad Request |
invalid_parameter |
unknown query parameter, invalid parameter value, invalid timezone, conflicting tz / TZ, or unsupported parameter on a route |
406 Not Acceptable |
unsupported_format |
requested response format is not supported by the endpoint/renderers |
Unhandled service or database errors are returned as server errors by the runtime.
Behavior Not Implemented
weatherapi does not implement pagination, cache-control headers, rate-limit
headers, idempotency keys, retries, writes, or historical browsing outside the
implemented latest-resource and forecast day-slice routes.
Endpoints
Observations
GET /observations
Returns the latest weather observation.
Query parameters: format, units, precision.
Metric data fields:
| Field | Type | Notes |
|---|---|---|
stationId, stationName |
string | optional |
timestamp |
RFC3339 datetime | required when data is not null |
conditionCode |
integer | WMO weather code |
isDay |
boolean | optional |
textDescription |
string | optional |
temperatureC, dewpointC, apparentTemperatureC |
number | optional |
windDirectionDegrees, windSpeedKmh, windGustKmh |
number | optional |
barometricPressurePa, visibilityMeters |
number | optional |
relativeHumidityPercent |
number | optional |
presentWeather |
array | optional |
US mode replaces unit-bearing fields with temperatureF, dewpointF,
apparentTemperatureF, windSpeedMph, windGustMph,
barometricPressureInHg, and visibilityMiles. Direction and percentage
fields keep the same names.
Example:
GET /observations?units=us&precision=1
Current Conditions
GET /conditions/current
Returns current conditions from recent observations rows. Numeric fields are
aggregated over the implemented 30-minute observation window. conditionCode
is selected from the latest observation per source in that window by
source-balanced WMO family consensus.
Query parameters: format, units, precision.
Common data fields:
| Field | Type | Notes |
|---|---|---|
conditionCode |
integer | WMO weather code selected by source-balanced family consensus |
conditionText |
string | optional text derived from WMO code and day/night flag |
isDay |
boolean | optional |
relativeHumidityPercent |
number | optional |
windDirectionDegrees |
number | optional |
Metric fields: temperatureC, apparentTemperatureC, dewpointC,
windSpeedKmh.
US fields: temperatureF, apparentTemperatureF, dewpointF,
windSpeedMph.
Example:
GET /conditions/current?format=json&precision=0
Active Alerts
GET /alerts/active
Returns the latest stored alert run filtered to alerts active at request time, omitting older alerts superseded by newer alert references in the same run.
Query parameters: format, units.
When no latest alert run exists, data is null. When a latest run exists but
no alerts are currently active, data remains an object and alerts is an
empty array.
Run data fields:
| Field | Type | Notes |
|---|---|---|
locationId, locationName |
string | optional |
asOf |
RFC3339 datetime | required when data is not null |
latitude, longitude |
number | optional |
alerts |
array | active alerts, possibly empty |
Alerts are active when messageType is not Cancel, effective is absent or
at or before request time, and the alert end boundary is absent or after request
time. The end boundary prefers ends; if ends is absent, expires is used as
a fallback for older rows or providers that do not supply an alert-period end.
onset is presented when available but is not used as the active boundary.
After active-time filtering, alerts referenced by another alert in the same run
are omitted as superseded. References from update and cancel messages are both
honored, even when the referencing alert is not itself returned.
Alert fields include id, event, headline, severity, urgency,
certainty, status, messageType, category, response, description,
instruction, sent, effective, onset, ends, expires,
areaDescription, senderName, and references. Most alert fields are
optional except id when an alert item is present. ends is the alert-period
end; expires is provider expiration metadata.
Reference fields are id, identifier, sender, and sent.
Example:
GET /alerts/active?format=text
Convective Outlooks
GET /outlooks/convective
GET /outlooks/convective/active
Returns the latest SPC convective outlook run reconstructed from
weatherfeeder-owned weather.outlook.v2 Postgres tables.
Route behavior:
/outlooks/convectivereturns the latest run with stored location-filtered outlook polygons unless user filters are supplied./outlooks/convective/activeadds an active-time filter using the server's current UTC time. Outlooks are active whenvalidFrom <= now < validTo.
When no latest run exists, data is null. When a run exists but filters match
no outlooks, data remains an object and outlooks and discussions are
empty arrays. Outlook endpoints use latest-run semantics and do not accumulate
historical active outlooks across older runs.
Query parameters:
| Parameter | Supported on | Values |
|---|---|---|
format, units, tz / TZ |
all outlook routes | shared rules above |
day |
all outlook routes | 1, 2, or 3 |
outlookType |
all outlook routes | categorical, tornado, hail, or wind |
outlookType values are normalized case-insensitively. Weatherfeeder v2
outlooks are already filtered for the configured location. precision,
containsLocation, and unknown parameters are rejected.
Run data fields:
| Field | Type | Notes |
|---|---|---|
locationId, locationName |
string | optional |
latitude, longitude |
number | optional |
asOf |
RFC3339 datetime | required when data is not null |
issuedAt |
RFC3339 datetime | optional |
outlooks |
array | ordered outlook polygons, possibly empty |
discussions |
array | ordered day-level discussions, possibly empty |
Outlook fields:
| Field | Type | Notes |
|---|---|---|
id, provider, product, outlookType, label |
string | required when an outlook is present |
day |
integer | SPC outlook day |
labelText, forecaster |
string | optional |
severityRank |
integer | optional |
validFrom, validTo, issuedAt, expiresAt |
RFC3339 datetime | required when an outlook is present |
sourceUrl, imageUrl |
string | optional |
containsLocation |
boolean | whether the outlook polygon contains the configured location |
geometry |
GeoJSON | stored outlook geometry |
Discussion fields:
| Field | Type | Notes |
|---|---|---|
day |
integer | SPC outlook day |
headline, summary, discussion |
string | optional |
updatedAt |
RFC3339 datetime | optional |
GeoJSON coordinates use standard GeoJSON coordinate order: longitude, then
latitude. Timezone conversion applies to run asOf, run issuedAt, and each
outlook's validFrom, validTo, issuedAt, and expiresAt, and discussion
updatedAt. Active filtering compares instants and is not changed by the
presentation timezone. Endpoint filters also filter discussions to days
represented by retained outlooks.
Examples:
GET /outlooks/convective?day=1&outlookType=categorical
GET /outlooks/convective/active?format=text&tz=CDT
Example JSON response:
{
"data": {
"locationId": "stl",
"locationName": "St. Louis",
"asOf": "2026-06-11T18:00:00Z",
"issuedAt": "2026-06-11T17:00:00Z",
"outlooks": [
{
"id": "spc-day1-cat-slight",
"provider": "spc",
"product": "convective",
"day": 1,
"outlookType": "categorical",
"label": "SLGT",
"labelText": "Slight Risk",
"severityRank": 5,
"validFrom": "2026-06-11T18:00:00Z",
"validTo": "2026-06-12T12:00:00Z",
"issuedAt": "2026-06-11T17:00:00Z",
"expiresAt": "2026-06-12T12:00:00Z",
"containsLocation": true,
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-91.0, 38.0],
[-90.0, 38.0],
[-90.0, 39.0],
[-91.0, 38.0]
]
]
}
}
],
"discussions": [
{
"day": 1,
"headline": "Severe storms possible",
"summary": "Scattered severe storms are possible.",
"discussion": "SPC discussion text.",
"updatedAt": "2026-06-11T17:30:00Z"
}
]
}
}
Text format uses the shared convective outlook template for both outlook routes
and renders a no-data message when data is null.
Forecasts
GET /forecast/hourly
GET /forecast/hourly/today
GET /forecast/hourly/tomorrow
GET /forecast/narrative
GET /forecast/narrative/today
GET /forecast/narrative/tomorrow
Returns the latest hourly or narrative forecast run. /today and /tomorrow
return a copy of the latest run with periods filtered by each period's
startTime in the resolved timezone. If no periods match, data remains an
object and periods is an empty array.
Query parameters: format, units, precision, tz / TZ.
Run data fields:
| Field | Type | Notes |
|---|---|---|
locationId, locationName |
string | optional |
issuedAt |
RFC3339 datetime | required when data is not null |
updatedAt |
RFC3339 datetime | optional |
product |
string | hourly or narrative for implemented routes |
latitude, longitude |
number | optional |
elevationMeters or elevationFeet |
number | optional, depends on units |
periods |
array | ordered forecast periods |
Metric period fields:
startTime, endTime, name, isDay, conditionCode,
textDescription, temperatureC, temperatureCMin, temperatureCMax,
dewpointC, relativeHumidityPercent, windDirectionDegrees,
windSpeedKmh, windGustKmh, barometricPressurePa, visibilityMeters,
apparentTemperatureC, cloudCoverPercent,
probabilityOfPrecipitationPercent, precipitationAmountMm,
snowfallDepthMm, and uvIndex.
US mode uses the same non-unit fields and replaces unit-bearing fields with
temperatureF, temperatureFMin, temperatureFMax, dewpointF,
windSpeedMph, windGustMph, barometricPressureInHg, visibilityMiles,
apparentTemperatureF, precipitationAmountIn, snowfallDepthIn, and
elevationFeet at run level.
startTime and endTime are required for each period. Other period fields are
optional, including conditionCode; narrative forecasts may omit it.
Examples:
GET /forecast/hourly?units=us&precision=1&TZ=-5
GET /forecast/narrative/tomorrow?format=text&tz=Chicago
Forecast Discussions
GET /discussion
GET /discussion/key-messages
GET /discussion/short-term
GET /discussion/long-term
Returns the latest forecast discussion or a focused subresource.
Query parameters: format, units, tz / TZ.
Full discussion data fields:
| Field | Type | Notes |
|---|---|---|
officeId, officeName |
string | optional |
product |
string | currently afd from weatherfeeder data |
issuedAt |
RFC3339 datetime | required when data is not null |
updatedAt |
RFC3339 datetime | optional |
keyMessages |
array of strings | optional |
shortTerm, longTerm |
object | optional section objects |
Discussion section fields are qualifier, issuedAt, and text, all
optional.
Subresources return the same metadata plus only their focused field:
keyMessages, shortTerm, or longTerm.
Example:
GET /discussion/short-term?format=text&tz=CDT
Weather Stories
GET /weatherstories
GET /weatherstories/latest
/weatherstories returns the latest weather-story run and its ordered stories.
/weatherstories/latest returns the latest individual story.
Query parameters: format, units, tz / TZ.
Run data fields:
| Field | Type | Notes |
|---|---|---|
officeId |
string | optional |
asOf |
RFC3339 datetime | required when data is not null |
stories |
array | ordered story objects |
Story fields:
| Field | Type | Notes |
|---|---|---|
officeId |
string | optional |
startTime, endTime, updatedAt |
RFC3339 datetime | required when a story is present |
title, description, altText, downloadUrl |
string | optional |
priority |
boolean | required when a story is present |
order |
integer | required when a story is present |
Examples:
GET /weatherstories?tz=America/Chicago
GET /weatherstories/latest?format=xml
Copyable Requests
See examples/requests.http for a compact set of
requests covering the implemented endpoint families.