GET /weather/forecast

Returns forecast weather variables for one GPS point and one forecast target: 2 m temperature, precipitation and 10 m wind, served from GFS data decoded from GRIB into a local grid store. The runtime lookup is local, so a covered target resolves in milliseconds without an account or API key.

This is the operational counterpart to GET /climate/point: use it when an agent needs a future weather signal for energy dispatch, logistics routing, agricultural planning or short-term risk checks. See the live /catalog for the authoritative endpoint listing and price.

x402 golden rule: the agent pays for the answer to its question. A well-formed and covered request is a successful answer -> 200, even when a requested variable is null because the grid cell has a data gap. Requests the service cannot answer - invalid coordinates, invalid target time, an uncovered forecast horizon, an unknown variable or a missing forecast cycle - leave the 200 range.

Parameters

ParameterTypeRequiredDescription
latnumberyesLatitude in decimal degrees, from -90 to 90
lonnumberyesLongitude in decimal degrees, from -180 to 180
horizon_hnumberone of target fieldsForecast lead in hours from the current GFS cycle, integer 0 to 384
valid_timestringone of target fieldsForecast target instant in RFC 3339 UTC form, for example 2026-06-20T12:00:00Z
variablesstringnoComma-separated subset of temperature, precipitation, wind; all by default

Provide exactly one of horizon_h or valid_time.

GET /weather/forecast?lat=48.8566&lon=2.3522&horizon_h=24
GET /weather/forecast?lat=48.8566&lon=2.3522&valid_time=2026-06-20T12:00:00Z

Use variables to reduce the payload when the agent only needs one family:

GET /weather/forecast?lat=48.8566&lon=2.3522&horizon_h=24&variables=temperature,wind

200 response - UnifiedResponse

{
  "data": { ... },
  "provenance": {
    "source": "gfs-noaa",
    "fetched_at": "2026-06-20T12:00:00Z",
    "freshness": { "kind": "live" }
  }
}
  • provenance.source: source identifier from the served GFS store, commonly gfs-noaa or GFS.
  • freshness.kind: live when the cycle is fresh, or cached with age_secs when a stale but still covered cycle is served.
  • GFS data comes from NOAA and is public-domain U.S. government data.

Fields of data

FieldTypeDescription
latnumberLatitude exactly echoed from the request
lonnumberLongitude exactly echoed from the request
horizon_hnumberEchoed when the request used horizon_h; omitted otherwise
valid_timestringEchoed when the request used valid_time; omitted otherwise
temperatureobjectRequested 2 m temperature; omitted when not requested
precipitationobjectRequested precipitation; omitted when not requested
windobjectRequested 10 m wind; omitted when not requested
gridobjectEffective grid cell used for the answer; omitted if no cell served
leadobjectResolved cycle, target and served model step
coverageobjectCompleteness marker for the requested variables

temperature

FieldTypeDescription
celsiusnumber | null2 m temperature in Celsius

precipitation

FieldTypeDescription
total_mmnumber | nullForecast precipitation total in millimetres

wind

FieldTypeDescription
speed_msnumber | null10 m wind speed in metres per second
direction_degnumber | nullMeteorological direction in degrees: 0 = north, 90 = east

grid

FieldTypeDescription
latnumberLatitude of the representative grid cell
lonnumberLongitude of the representative grid cell
distance_kmnumberDistance from the requested point to that cell

lead

lead makes the resolved forecast target explicit, whether the caller supplied horizon_h or valid_time.

FieldTypeDescription
cyclestringGFS analysis cycle used for the answer, RFC 3339 UTC
valid_timestringResolved target instant, RFC 3339 UTC
horizon_hnumberLead time in hours from cycle to valid_time
step_timestring | nullActual model step served; omitted if no step was served

coverage

coverage tells the agent whether every requested variable was actually available at the served grid cell.

FieldTypeDescription
completebooltrue when all requested variables have values
reasonstringPresent when complete: false, naming the missing family data

Example - horizon target

{
  "data": {
    "lat": 48.8566,
    "lon": 2.3522,
    "horizon_h": 24,
    "temperature": { "celsius": 18.6 },
    "precipitation": { "total_mm": 0.4 },
    "wind": { "speed_ms": 6.1, "direction_deg": 242.3 },
    "grid": { "lat": 48.75, "lon": 2.25, "distance_km": 13.42 },
    "lead": {
      "cycle": "2026-06-20T00:00:00Z",
      "valid_time": "2026-06-21T00:00:00Z",
      "horizon_h": 24,
      "step_time": "2026-06-21T00:00:00Z"
    },
    "coverage": { "complete": true }
  },
  "provenance": {
    "source": "gfs-noaa",
    "fetched_at": "2026-06-20T01:20:00Z",
    "freshness": { "kind": "live" }
  }
}

Example - explicit valid_time

When the request uses valid_time, that field is echoed and horizon_h is omitted from the top-level data. The resolved lead still carries the computed horizon.

{
  "data": {
    "lat": 48.8566,
    "lon": 2.3522,
    "valid_time": "2026-06-21T00:00:00Z",
    "temperature": { "celsius": 18.6 },
    "precipitation": { "total_mm": 0.4 },
    "wind": { "speed_ms": 6.1, "direction_deg": 242.3 },
    "grid": { "lat": 48.75, "lon": 2.25, "distance_km": 13.42 },
    "lead": {
      "cycle": "2026-06-20T00:00:00Z",
      "valid_time": "2026-06-21T00:00:00Z",
      "horizon_h": 24,
      "step_time": "2026-06-21T00:00:00Z"
    },
    "coverage": { "complete": true }
  },
  "provenance": {
    "source": "gfs-noaa",
    "fetched_at": "2026-06-20T01:20:00Z",
    "freshness": { "kind": "live" }
  }
}

Example - stale but covered cycle

A stale cycle can still answer a covered target. It remains a 200, with freshness.kind = "cached" and an age in seconds so the agent can decide whether to trust or retry later.

{
  "data": {
    "lat": 48.8566,
    "lon": 2.3522,
    "horizon_h": 3,
    "temperature": { "celsius": 17.1 },
    "precipitation": { "total_mm": 0.0 },
    "wind": { "speed_ms": 4.2, "direction_deg": 190.0 },
    "grid": { "lat": 48.75, "lon": 2.25, "distance_km": 13.42 },
    "lead": {
      "cycle": "2026-06-20T00:00:00Z",
      "valid_time": "2026-06-20T03:00:00Z",
      "horizon_h": 3,
      "step_time": "2026-06-20T03:00:00Z"
    },
    "coverage": { "complete": true }
  },
  "provenance": {
    "source": "gfs-noaa",
    "fetched_at": "2026-06-20T09:30:00Z",
    "freshness": { "kind": "cached", "age_secs": 34200 }
  }
}

Coverage honesty

GFS is a gridded forecast model, not a weather station reading. The response is the nearest or interpolated grid value for the served cell, with a typical global mesh of about 0.25 degrees. Forecast steps are discrete, commonly around 3 hours, and the public horizon is bounded by the currently ingested forecast window - about the next 4 to 5 days. (The GFS model itself extends to 384 hours; the ingested horizon will be widened toward it, and this page updated, when that lands.)

A target inside the available forecast window can return 200 with null values and coverage.complete: false when the grid has a local gap. A target outside the available window returns 400 OUT_OF_RANGE, because the service cannot answer the request. If no GFS cycle has been ingested yet, the service returns 503 NO_FORECAST_AVAILABLE; that is a transient no-charge state, not a paid partial answer.

Errors

Only requests the service cannot answer leave the 200 range.

StatuscodeCase
400INVALID_COORDSlat/lon missing, non-numeric or outside valid bounds
400INVALID_TIMEMissing target, both target fields present, malformed RFC 3339, or horizon_h outside 0..384
400OUT_OF_RANGETarget is outside the available forecast window
400INVALID_VARIABLEvariables contains a family outside the supported set
503NO_FORECAST_AVAILABLENo GFS forecast cycle is currently available in the store
500INTERNALInternal error (detail logged, not exposed)
{ "error": "one of valid_time or horizon_h is required", "code": "INVALID_TIME" }
{ "error": "requested lead time is outside the available forecast window 2026-06-20T00:00:00+00:00..2026-06-20T06:00:00+00:00", "code": "OUT_OF_RANGE" }
{ "error": "no GFS forecast cycle currently available", "code": "NO_FORECAST_AVAILABLE" }

See also

  • GET /climate/point - historical ERA5 reanalysis for dated climate evidence.
  • For agents - discovery surfaces, the live /catalog and how settlement works.