GribStream

Quick start guide

Sign in, create an API token (there is a free tier!), and make a first request. Copy‑paste any of the examples below (cURL / Python). Swap tokens & timestamps and you’re live. Replace wherever you see [TOKEN] with your token (without the brackets!).

1. Doing a simple request

Query hourly temperature data for May 1st 2025 at Times Square according to NOAA's Global Forecast System (GFS).

URL:

We'll be requesting to this endpoint:

POST https://gribstream.com/api/v2/[MODEL]/history

So replace [MODEL] with the code for GFS which is gfs so it looks like this:

POST https://gribstream.com/api/v2/gfs/history

You can check all available models here

Payload:

Timestamps are in ISO 8601 UTC format and we will be requesting a time range, from fromTime to untilTime.

Coordinates are (latitude, longitude) floating point pairs

Weather parameters are selected by (name, level, info) truples. name and level are mandatory but info is only required when models provide multiple options for the same dimension and level. Looking at GFS, you'll see temperature is available with the TMP name at many levels. Let's use 2m above ground for this example.

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H [API_TOKEN] \
-d '{
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [{ "lat": 40.758, "lon": -73.985 }],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "" }]
}'
import requests

API_TOKEN = "[API_TOKEN]"  # Replace with your token

payload = {
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [
        { "lat": 40.758, "lon": -73.985 }
    ],
    "variables": [
        { "name": "TMP", "level": "2 m above ground", "info": "" }
    ]
}

headers = {
    "Authorization": f"Bearer {API_TOKEN}",
}

response = requests.post("https://gribstream.com/api/v2/nbm/history", json=payload, headers=headers)
response.raise_for_status()

print(response.text)

Output:

forecasted_at,forecasted_time,lat,lon,name,TMP|2 m above ground|
2025-05-01T06:00:00Z,2025-05-01T09:00:00Z,40.7580,-73.9850,,286.7000
2025-05-01T06:00:00Z,2025-05-01T11:00:00Z,40.7580,-73.9850,,286.5539
2025-05-01T00:00:00Z,2025-05-01T01:00:00Z,40.7580,-73.9850,,292.2532
2025-05-01T12:00:00Z,2025-05-01T15:00:00Z,40.7580,-73.9850,,292.2911
2025-05-01T18:00:00Z,2025-05-01T19:00:00Z,40.7580,-73.9850,,292.7923
2025-05-01T12:00:00Z,2025-05-01T14:00:00Z,40.7580,-73.9850,,290.9911
2025-05-01T12:00:00Z,2025-05-01T17:00:00Z,40.7580,-73.9850,,293.8677
2025-05-01T12:00:00Z,2025-05-01T16:00:00Z,40.7580,-73.9850,,293.2000
2025-05-01T18:00:00Z,2025-05-01T20:00:00Z,40.7580,-73.9850,,292.3354
2025-05-01T18:00:00Z,2025-05-01T18:00:00Z,40.7580,-73.9850,,293.5384
2025-05-01T06:00:00Z,2025-05-01T08:00:00Z,40.7580,-73.9850,,287.1673
2025-05-01T12:00:00Z,2025-05-01T13:00:00Z,40.7580,-73.9850,,289.4673
2025-05-01T00:00:00Z,2025-05-01T04:00:00Z,40.7580,-73.9850,,289.4754
2025-05-01T00:00:00Z,2025-05-01T03:00:00Z,40.7580,-73.9850,,290.4711
2025-05-01T00:00:00Z,2025-05-01T05:00:00Z,40.7580,-73.9850,,288.8000
2025-05-01T00:00:00Z,2025-05-01T00:00:00Z,40.7580,-73.9850,,292.9684
2025-05-01T12:00:00Z,2025-05-01T12:00:00Z,40.7580,-73.9850,,287.7405
2025-05-01T00:00:00Z,2025-05-01T02:00:00Z,40.7580,-73.9850,,291.3480
2025-05-01T06:00:00Z,2025-05-01T06:00:00Z,40.7580,-73.9850,,288.2327
2025-05-01T06:00:00Z,2025-05-01T10:00:00Z,40.7580,-73.9850,,286.2595
2025-05-01T18:00:00Z,2025-05-01T22:00:00Z,40.7580,-73.9850,,290.9539
2025-05-01T06:00:00Z,2025-05-01T07:00:00Z,40.7580,-73.9850,,287.7000
2025-05-01T18:00:00Z,2025-05-01T23:00:00Z,40.7580,-73.9850,,290.0113
2025-05-01T18:00:00Z,2025-05-01T21:00:00Z,40.7580,-73.9850,,291.8027

Notice the rows are not in forecasted_at nor forecasted_time order. This is for API efficiency.

2. Location names and variable aliases

When parsing the response it can be very convenient to use names instead of the coordinate pair. You can use it to give the location a human readable name or to store an ID. This is useful to create visualizations and dashboards with no pre-processing. You achieve this by adding an extra name property to each coordinate. In this case we'll use TimesSquare

Similarly, the three part naming convention for weather variables can be ugly to human eyes (TMP|2 m above ground| 🤮) so you can rename the variable with an extra property called alias. It can be useful to programatically switch between temperatures at different levels but still call the variable just temp. Think of it as the keyword "as" in SQL.

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Authorization: Bearer [API_TOKEN] \
-d '{
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [{ "lat": 40.758, "lon": -73.985 , "name": "TimesSquare"}],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'
import requests

API_TOKEN = "[API_TOKEN]"  # Replace with your token

payload = {
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [
        { "lat": 40.758, "lon": -73.985, "name": "TimesSquare" }
    ],
    "variables": [
        { "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }
    ]
}

headers = {
    "Authorization": f"Bearer {API_TOKEN}",
}

response = requests.post("https://gribstream.com/api/v2/nbm/history", json=payload, headers=headers)
response.raise_for_status()

print(response.text)

Output:

forecasted_at,forecasted_time,lat,lon,name,temp
2025-05-01T05:00:00Z,2025-05-01T06:00:00Z,40.7580,-73.9850,TimesSquare,287.7400
2025-05-01T10:00:00Z,2025-05-01T11:00:00Z,40.7580,-73.9850,TimesSquare,285.7200
2025-05-01T03:00:00Z,2025-05-01T04:00:00Z,40.7580,-73.9850,TimesSquare,289.1600
2025-05-01T08:00:00Z,2025-05-01T09:00:00Z,40.7580,-73.9850,TimesSquare,285.7200
2025-05-01T20:00:00Z,2025-05-01T21:00:00Z,40.7580,-73.9850,TimesSquare,291.7000
2025-05-01T04:00:00Z,2025-05-01T05:00:00Z,40.7580,-73.9850,TimesSquare,288.4300
2025-05-01T02:00:00Z,2025-05-01T03:00:00Z,40.7580,-73.9850,TimesSquare,290.1200
2025-05-01T09:00:00Z,2025-05-01T10:00:00Z,40.7580,-73.9850,TimesSquare,285.4300
2025-05-01T06:00:00Z,2025-05-01T07:00:00Z,40.7580,-73.9850,TimesSquare,286.8900
2025-05-01T19:00:00Z,2025-05-01T20:00:00Z,40.7580,-73.9850,TimesSquare,292.5500
2025-05-01T07:00:00Z,2025-05-01T08:00:00Z,40.7580,-73.9850,TimesSquare,286.3500
2025-05-01T15:00:00Z,2025-05-01T16:00:00Z,40.7580,-73.9850,TimesSquare,292.9300
2025-05-01T11:00:00Z,2025-05-01T12:00:00Z,40.7580,-73.9850,TimesSquare,286.8000
2025-05-01T18:00:00Z,2025-05-01T19:00:00Z,40.7580,-73.9850,TimesSquare,293.4100
2025-05-01T17:00:00Z,2025-05-01T18:00:00Z,40.7580,-73.9850,TimesSquare,293.8500
2025-05-01T12:00:00Z,2025-05-01T13:00:00Z,40.7580,-73.9850,TimesSquare,288.1300
2025-05-01T21:00:00Z,2025-05-01T22:00:00Z,40.7580,-73.9850,TimesSquare,291.0500
2025-05-01T13:00:00Z,2025-05-01T14:00:00Z,40.7580,-73.9850,TimesSquare,290.2100
2025-05-01T14:00:00Z,2025-05-01T15:00:00Z,40.7580,-73.9850,TimesSquare,291.3900
2025-05-01T01:00:00Z,2025-05-01T02:00:00Z,40.7580,-73.9850,TimesSquare,291.2300
2025-05-01T00:00:00Z,2025-05-01T01:00:00Z,40.7580,-73.9850,TimesSquare,291.6000
2025-05-01T16:00:00Z,2025-05-01T17:00:00Z,40.7580,-73.9850,TimesSquare,293.6300
2025-04-30T23:00:00Z,2025-05-01T00:00:00Z,40.7580,-73.9850,TimesSquare,292.6500
2025-05-01T22:00:00Z,2025-05-01T23:00:00Z,40.7580,-73.9850,TimesSquare,289.6300

Pretty, eh?.

3. Response formats

The format of the response is determined by the Accept header. The API supports three response formats:

  • Accept: text/csv - the response is a CSV file containing the forecast data.
  • Accept: application/json - each line in the response is a separate JSON object.
  • Accept: application/ndjson - the response is a single JSON array of objects.

If not format is specified, the response format defaults to text/csv

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Authorization: Bearer [API_TOKEN] \
-H "Accept: text/csv" \
-d '{
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [{ "lat": 40.758, "lon": -73.985 , "name": "TimesSquare"}],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,temp
2025-05-01T05:00:00Z,2025-05-01T06:00:00Z,40.7580,-73.9850,TimesSquare,287.7400
2025-05-01T10:00:00Z,2025-05-01T11:00:00Z,40.7580,-73.9850,TimesSquare,285.7200
2025-05-01T03:00:00Z,2025-05-01T04:00:00Z,40.7580,-73.9850,TimesSquare,289.1600
2025-05-01T08:00:00Z,2025-05-01T09:00:00Z,40.7580,-73.9850,TimesSquare,285.7200
2025-05-01T20:00:00Z,2025-05-01T21:00:00Z,40.7580,-73.9850,TimesSquare,291.7000
2025-05-01T04:00:00Z,2025-05-01T05:00:00Z,40.7580,-73.9850,TimesSquare,288.4300
2025-05-01T02:00:00Z,2025-05-01T03:00:00Z,40.7580,-73.9850,TimesSquare,290.1200
2025-05-01T09:00:00Z,2025-05-01T10:00:00Z,40.7580,-73.9850,TimesSquare,285.4300
2025-05-01T06:00:00Z,2025-05-01T07:00:00Z,40.7580,-73.9850,TimesSquare,286.8900
2025-05-01T19:00:00Z,2025-05-01T20:00:00Z,40.7580,-73.9850,TimesSquare,292.5500
2025-05-01T07:00:00Z,2025-05-01T08:00:00Z,40.7580,-73.9850,TimesSquare,286.3500
2025-05-01T15:00:00Z,2025-05-01T16:00:00Z,40.7580,-73.9850,TimesSquare,292.9300
2025-05-01T11:00:00Z,2025-05-01T12:00:00Z,40.7580,-73.9850,TimesSquare,286.8000
2025-05-01T18:00:00Z,2025-05-01T19:00:00Z,40.7580,-73.9850,TimesSquare,293.4100
2025-05-01T17:00:00Z,2025-05-01T18:00:00Z,40.7580,-73.9850,TimesSquare,293.8500
2025-05-01T12:00:00Z,2025-05-01T13:00:00Z,40.7580,-73.9850,TimesSquare,288.1300
2025-05-01T21:00:00Z,2025-05-01T22:00:00Z,40.7580,-73.9850,TimesSquare,291.0500
2025-05-01T13:00:00Z,2025-05-01T14:00:00Z,40.7580,-73.9850,TimesSquare,290.2100
2025-05-01T14:00:00Z,2025-05-01T15:00:00Z,40.7580,-73.9850,TimesSquare,291.3900
2025-05-01T01:00:00Z,2025-05-01T02:00:00Z,40.7580,-73.9850,TimesSquare,291.2300
2025-05-01T00:00:00Z,2025-05-01T01:00:00Z,40.7580,-73.9850,TimesSquare,291.6000
2025-05-01T16:00:00Z,2025-05-01T17:00:00Z,40.7580,-73.9850,TimesSquare,293.6300
2025-04-30T23:00:00Z,2025-05-01T00:00:00Z,40.7580,-73.9850,TimesSquare,292.6500
2025-05-01T22:00:00Z,2025-05-01T23:00:00Z,40.7580,-73.9850,TimesSquare,289.6300

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Authorization: Bearer [API_TOKEN] \
-H "Accept: application/json" \
-d '{
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [{ "lat": 40.758, "lon": -73.985 , "name": "TimesSquare"}],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'

Output:

[{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T00:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.96841796875}
,{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T11:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":286.553857421875}
,{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T05:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":288.80002441406253}
,{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T04:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":289.4754296875}
,{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T17:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":293.86765136718753}
,{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T13:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":289.46726074218753}
,{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T14:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.99106445312503}
,{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T19:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.7922607421875}
,{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T18:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":293.53837890625005}
,{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T20:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.33542480468753}
,{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T15:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.29106445312505}
,{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T21:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":291.802685546875}
,{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T09:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":286.70000000000005}
,{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T06:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":288.23271484375}
,{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T07:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":287.70000000000005}
,{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T22:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.953857421875}
,{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T08:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":287.1672607421875}
,{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T10:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":286.2595458984375}
,{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T12:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":287.74045410156253}
,{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T16:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":293.20000000000005}
,{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T02:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":291.348046875}
,{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T03:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.47107421875}
,{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T01:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.25318359375}
,{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T23:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.0113037109375}
]

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Authorization: Bearer [API_TOKEN] \
-H "Accept: application/ndjson" \
-d '{
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "coordinates": [{ "lat": 40.758, "lon": -73.985 , "name": "TimesSquare"}],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'

Output:

{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T12:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":287.74045410156253}
{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T05:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":288.80002441406253}
{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T15:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.29106445312505}
{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T06:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":288.23271484375}
{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T16:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":293.20000000000005}
{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T22:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.953857421875}
{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T01:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.25318359375}
{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T02:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":291.348046875}
{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T03:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.47107421875}
{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T13:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":289.46726074218753}
{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T04:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":289.4754296875}
{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T14:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.99106445312503}
{"forecasted_at":"2025-05-01T00:00:00Z","forecasted_time":"2025-05-01T00:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.96841796875}
{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T07:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":287.70000000000005}
{"forecasted_at":"2025-05-01T12:00:00Z","forecasted_time":"2025-05-01T17:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":293.86765136718753}
{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T08:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":287.1672607421875}
{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T18:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":293.53837890625005}
{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T09:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":286.70000000000005}
{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T19:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.7922607421875}
{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T10:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":286.2595458984375}
{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T20:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":292.33542480468753}
{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T21:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":291.802685546875}
{"forecasted_at":"2025-05-01T06:00:00Z","forecasted_time":"2025-05-01T11:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":286.553857421875}
{"forecasted_at":"2025-05-01T18:00:00Z","forecasted_time":"2025-05-01T23:00:00Z","lat":40.758,"lon":-73.985,"name":"TimesSquare","temp":290.0113037109375}
4. Select times by enumeration instead of range

Sometimes it can be useful to select a list of specific times instead of a range of time. For that you can use the timesList argument in the request with each specific hour expected in the response.

For example, query the weather during New Year 🎉🥳🕛🍾🥂 2022, 2023, 2024 and 2025

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Authorization: Bearer [API_TOKEN]" \
-d '{
    "timesList": [
        "2022-01-01T00:00:00Z",
        "2023-01-01T00:00:00Z",
        "2024-01-01T00:00:00Z",
        "2025-01-01T00:00:00Z"
    ],
    "coordinates": [{ "lat": 40.758, "lon": -73.985 , "name": "TimesSquare"}],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,temp
2022-01-01T00:00:00Z,2022-01-01T00:00:00Z,40.7580,-73.9850,TimesSquare,283.1841
2024-01-01T00:00:00Z,2024-01-01T00:00:00Z,40.7580,-73.9850,TimesSquare,279.0649
2023-01-01T00:00:00Z,2023-01-01T00:00:00Z,40.7580,-73.9850,TimesSquare,281.7180
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,40.7580,-73.9850,TimesSquare,281.8039
5. Select locations by grid

Instead of querying data for specific coordinates you can define a grid of minLatitude, maxLatitude, minLongitude, maxLongitude, step where step is the resolution in degrees.

Here is a nice visual example with our demo of wind fields

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Authorization: Bearer [API_TOKEN]" \
-d '{
    "timesList": [ "2025-01-01T00:00:00Z" ],
    "grid": {
        "minLatitude": 25.00,
        "maxLatitude": 27.00,
        "minLongitude": -122.00,
        "maxLongitude": -120.00,
        "step": 0.5
    },
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,temp
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,27.0000,-122.0000,,290.0439
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,27.0000,-121.5000,,289.8739
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,27.0000,-121.0000,,289.7339
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,27.0000,-120.5000,,289.6239
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,27.0000,-120.0000,,289.5039
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.5000,-122.0000,,290.2839
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.5000,-121.5000,,290.1139
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.5000,-121.0000,,289.9739
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.5000,-120.5000,,289.8339
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.5000,-120.0000,,289.7239
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.0000,-122.0000,,290.5739
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.0000,-121.5000,,290.4239
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.0000,-121.0000,,290.2439
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.0000,-120.5000,,290.0339
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,26.0000,-120.0000,,289.8339
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.5000,-122.0000,,290.9539
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.5000,-121.5000,,290.7239
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.5000,-121.0000,,290.4739
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.5000,-120.5000,,290.2339
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.5000,-120.0000,,290.0439
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.0000,-122.0000,,291.1239
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.0000,-121.5000,,290.9539
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.0000,-121.0000,,290.7139
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.0000,-120.5000,,290.4539
2025-01-01T00:00:00Z,2025-01-01T00:00:00Z,25.0000,-120.0000,,290.2239
6. Forecast horizon filtering (min_horizon, max_horizon)

The forecast horizon is the time difference (in hours) between when a forecast was issued (forecasted_at) and the time it predicts (forecasted_time).

  • min_horizon: Only include values forecasted at least this many hours ahead. Useful to see “How well did the model do at predicting the future N+ hours out?”
  • max_horizon: Only include values forecasted at most this many hours ahead. Useful to limit results to short-term predictions, or to exclude stale/long-range forecasts.
In other words, these parameters control the minimum and maximum "lead time" for each forecasted value you retrieve.

Example: To see only values that were predicted at least 12 hours in advance:

Code:

curl -X POST 'https://gribstream.com/api/v2/nbm/history' \
-H "Authorization: Bearer [API_TOKEN]" \
-d '{
    "fromTime": "2025-05-01T12:00:00Z",
    "untilTime": "2025-05-01T18:00:00Z",
    "minHorizon": 12,
    "coordinates": [{ "lat": 40.758, "lon": -73.985, "name": "TimesSquare" }],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "alias": "temp" }]
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,temp,horizon_hours
            2025-05-01T00:00:00Z,2025-05-01T12:00:00Z,40.7580,-73.9850,TimesSquare,286.6700
            2025-05-01T01:00:00Z,2025-05-01T13:00:00Z,40.7580,-73.9850,TimesSquare,288.0300
            2025-05-01T02:00:00Z,2025-05-01T14:00:00Z,40.7580,-73.9850,TimesSquare,289.5900
            2025-05-01T03:00:00Z,2025-05-01T15:00:00Z,40.7580,-73.9850,TimesSquare,290.9600
            2025-05-01T04:00:00Z,2025-05-01T16:00:00Z,40.7580,-73.9850,TimesSquare,292.3300
            2025-05-01T05:00:00Z,2025-05-01T17:00:00Z,40.7580,-73.9850,TimesSquare,293.1900

Note: Rows are presented here sorted by forecasted_at to make the result easier to grok.

Another example: To only include short-range predictions up to 3 hours out:

curl -X POST 'https://gribstream.com/api/v2/nbm/history' \
-H "Authorization: Bearer [API_TOKEN]" \
-d '{
    "fromTime": "2025-05-01T12:00:00Z",
    "untilTime": "2025-05-01T15:00:00Z",
    "maxHorizon": 3,
    "coordinates": [{ "lat": 40.758, "lon": -73.985 }],
    "variables": [{ "name": "TMP", "level": "2 m above ground" }]
}'

Use min_horizon and max_horizon together to restrict the forecasted values to any desired prediction window.

Tip: Unlike the asOf parameter (see next example), which restricts results to only data available before a certain time, min_horizon and max_horizon filter by the age of the forecast relative to the predicted value.

7. As-of or time-travel (for backtesting)

When backtesting predictive models, it's essential to query data as it was known at a specific point in time, not after the fact.

For example: “What was the forecast for May 1st, based on what was available by April 30th at 12:00 UTC?”

This is called a time-travel query: it returns only the data that was available as of the specified moment in the past, not any newer corrections or updates.

Code:

curl -X POST 'https://gribstream.com/api/v2/nbm/history' \
-H "Authorization: Bearer [API_TOKEN]" \
-d '{
    "fromTime": "2025-05-01T00:00:00Z",
    "untilTime": "2025-05-02T00:00:00Z",
    "asOf": "2025-05-01T12:00:00Z",
    "coordinates": [{ "lat": 40.758, "lon": -73.985 , "name": "TimesSquare"}],
    "variables": [{ "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" }]
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,temp
2025-04-30T23:00:00Z,2025-05-01T00:00:00Z,40.7580,-73.9850,TimesSquare,292.6500
2025-05-01T00:00:00Z,2025-05-01T01:00:00Z,40.7580,-73.9850,TimesSquare,291.6000
2025-05-01T01:00:00Z,2025-05-01T02:00:00Z,40.7580,-73.9850,TimesSquare,291.2300
2025-05-01T02:00:00Z,2025-05-01T03:00:00Z,40.7580,-73.9850,TimesSquare,290.1200
2025-05-01T03:00:00Z,2025-05-01T04:00:00Z,40.7580,-73.9850,TimesSquare,289.1600
2025-05-01T04:00:00Z,2025-05-01T05:00:00Z,40.7580,-73.9850,TimesSquare,288.4300
2025-05-01T05:00:00Z,2025-05-01T06:00:00Z,40.7580,-73.9850,TimesSquare,287.7400
2025-05-01T06:00:00Z,2025-05-01T07:00:00Z,40.7580,-73.9850,TimesSquare,286.8900
2025-05-01T07:00:00Z,2025-05-01T08:00:00Z,40.7580,-73.9850,TimesSquare,286.3500
2025-05-01T08:00:00Z,2025-05-01T09:00:00Z,40.7580,-73.9850,TimesSquare,285.7200
2025-05-01T09:00:00Z,2025-05-01T10:00:00Z,40.7580,-73.9850,TimesSquare,285.4300
2025-05-01T10:00:00Z,2025-05-01T11:00:00Z,40.7580,-73.9850,TimesSquare,285.7200
2025-05-01T11:00:00Z,2025-05-01T12:00:00Z,40.7580,-73.9850,TimesSquare,286.8000
2025-05-01T12:00:00Z,2025-05-01T13:00:00Z,40.7580,-73.9850,TimesSquare,288.1300
2025-05-01T12:00:00Z,2025-05-01T14:00:00Z,40.7580,-73.9850,TimesSquare,290.1600
2025-05-01T12:00:00Z,2025-05-01T15:00:00Z,40.7580,-73.9850,TimesSquare,291.3400
2025-05-01T12:00:00Z,2025-05-01T16:00:00Z,40.7580,-73.9850,TimesSquare,292.6500
2025-05-01T12:00:00Z,2025-05-01T17:00:00Z,40.7580,-73.9850,TimesSquare,293.0100
2025-05-01T12:00:00Z,2025-05-01T18:00:00Z,40.7580,-73.9850,TimesSquare,293.1500
2025-05-01T12:00:00Z,2025-05-01T19:00:00Z,40.7580,-73.9850,TimesSquare,292.7500
2025-05-01T12:00:00Z,2025-05-01T20:00:00Z,40.7580,-73.9850,TimesSquare,292.1500
2025-05-01T12:00:00Z,2025-05-01T21:00:00Z,40.7580,-73.9850,TimesSquare,291.3500
2025-05-01T12:00:00Z,2025-05-01T22:00:00Z,40.7580,-73.9850,TimesSquare,290.7100
2025-05-01T12:00:00Z,2025-05-01T23:00:00Z,40.7580,-73.9850,TimesSquare,289.5800

Note: Rows are presented here sorted by forecasted_at to make the result easier to grok.

This example uses the NOAA National Blend of Models (NBM), which runs hourly. Notice that forecasted_at is always the hour previous to forecasted_time, meaning the best forecast for that hour, except for times after asOf which is set to 2025-05-01T12:00:00Z. Model runs after that time are excluded.

8. Calculated expressions (derived values, computed fields, formulas, etc)

GribStream lets you define expressions to calculate derived columns, transformations, and boolean filters in your API queries.

Expressions use the expr language, supporting numeric, logical, and string operations with access to math functions.

To see a really cool demo dashboard doing a single API request see: Corn growth simulation

Features

  • Use dataset columns and previously calculated expressions as inputs
  • Chain expressions: later expressions can use the results of earlier ones
  • Apply boolean filters to include or exclude rows
  • Leverage a set of math functions registered by GribStream (see below)

Example expressions

  • Wind speed from U/V components: func.Hypot(uwind, vwind)
  • Wind direction in meteorological degrees: int(270 - func.Atan2(vwind, uwind) * 180 / 3.14159) % 360
  • Filter for strong surface wind: func.Hypot(uwind, vwind) > 10

Code:

curl -X POST 'https://gribstream.com/api/v2/hrrr/history' \
-H "Content-Type: application/json" \
-H "Authorization: [API_TOKEN]" \
-d '{
    "fromTime": "2024-09-10T00:00:00Z",
    "untilTime": "2024-09-10T10:00:00Z",
    "coordinates": [{ "lat": 40.7306, "lon": -73.9352, "name": "New York City" }],
    "variables": [
    { "name": "UGRD", "level": "1000 mb", "alias": "uwind" },
    { "name": "VGRD", "level": "1000 mb", "alias": "vwind" }
    ],
    "expressions": [
    { "expression": "func.Hypot(uwind, vwind)", "alias": "wind_magnitude" },
    { "expression": "int(270 - func.Atan2(vwind, uwind) * 180 / 3.14159) % 360", "alias": "wind_direction" }
    ]
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,uwind,vwind,wind_direction,wind_magnitude
2024-09-10T02:00:00Z,2024-09-10T03:00:00Z,40.7306,-73.9352,New York City,7.1213,1.7680,256,7.3375
2024-09-10T01:00:00Z,2024-09-10T02:00:00Z,40.7306,-73.9352,New York City,8.1815,1.6363,258,8.3435
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,40.7306,-73.9352,New York City,8.0572,2.9389,249,8.5765
2024-09-10T05:00:00Z,2024-09-10T06:00:00Z,40.7306,-73.9352,New York City,6.8368,0.1001,269,6.8375
2024-09-10T04:00:00Z,2024-09-10T05:00:00Z,40.7306,-73.9352,New York City,6.4087,3.0921,244,7.1157
2024-09-10T03:00:00Z,2024-09-10T04:00:00Z,40.7306,-73.9352,New York City,6.4841,2.5385,248,6.9633
2024-09-09T23:00:00Z,2024-09-10T00:00:00Z,40.7306,-73.9352,New York City,6.1795,3.9539,237,7.3362
2024-09-10T08:00:00Z,2024-09-10T09:00:00Z,40.7306,-73.9352,New York City,5.9424,-0.6889,276,5.9822
2024-09-10T06:00:00Z,2024-09-10T07:00:00Z,40.7306,-73.9352,New York City,7.3567,1.5594,258,7.5201
2024-09-10T07:00:00Z,2024-09-10T08:00:00Z,40.7306,-73.9352,New York City,6.5438,0.7486,263,6.5864
9. Filtering or searching for conditions using calculated expressions

GribStream lets you define expressions to filter in space and time, only returning data matching the condition.

Filtering expressions follow the same syntax of calculated expressions but they must evaluate to true or false.

To see a really cool demo dashboard doing a single API request see: Storm chasers

Code:

curl -X POST 'https://gribstream.com/api/v2/gfs/history' \
-H "Content-Type: application/json" \
-H "Authorization: [API_TOKEN] \
-d '{
    "fromTime": "2024-09-10T00:00:00Z",
    "untilTime": "2024-09-10T10:00:00Z",
    "grid": {
            "minLatitude": 24.52,
            "maxLatitude": 49.38,
            "minLongitude": -124.77,
            "maxLongitude": -66.93,
            "step": 0.5
        },
        "variables": [
            {"name": "CAPE", "level": "180-0 mb above ground", "info": "", "alias": "cape"},
            {"name": "CIN", "level": "180-0 mb above ground", "info": "", "alias": "cin"}
        ],
        "expressions":[
            { "expression": "cape + cin", "alias": "storm_severity"}
        ],
        "filter":{"expression": "storm_severity >= 1200"}
}'

Output:

forecasted_at,forecasted_time,lat,lon,name,cape,cin,offset_hours,storm_severity
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,29.0200,-70.7700,,1337.0000,-1.6324,-5713.0000,1335.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,29.0200,-70.2700,,1204.0000,-1.6324,-5713.0000,1202.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.5200,-71.7700,,1432.0000,-0.6324,-5713.0000,1431.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.5200,-71.2700,,1384.0000,-1.6324,-5713.0000,1382.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.5200,-70.7700,,1355.0000,-0.6324,-5713.0000,1354.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.5200,-70.2700,,1388.0000,-1.6324,-5713.0000,1386.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.0200,-112.2700,,1599.0000,-148.6324,-5713.0000,1450.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.0200,-111.2700,,1424.0000,-104.6324,-5713.0000,1319.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.0200,-75.2700,,1328.0000,-0.6324,-5713.0000,1327.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.0200,-74.7700,,1242.0000,-1.6324,-5713.0000,1240.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.0200,-73.2700,,1327.0000,0.3676,-5713.0000,1327.3676
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,28.0200,-72.7700,,1471.0000,0.3676,-5713.0000,1471.3676
...
10. Retrieving full forecast history

All previous examples use the history endpoint. It's purpose is to return the "best" forecast possible for all times. The best forecast is always the most recent one or said differently the one with the lowest horizon. The minHorizon, maxHorizon and asOf parameters allow specifying restrictions on what model runs are to be taken into consideration but for any forecasted value a single model run is chosen.

If what we are actually looking for is to retrieve all forecasts of each value then we need to leverage the forecasts endpoint.

POST https://gribstream.com/api/v2/[MODEL]/forecasts

This endpoint chooses the time range based on parameters named forecastedFrom and forecastedUntil to make it clear that the data is being selected based on the time the forecast is made. Specifying model run times by enumeration with the timesList parameter is also an option and it is useful when looking for specific model run times.

All other parameters remain available and the same except asOf that is not available. So you can filter by minHorizon and maxHorizon, define expressions with calculated values, filter by them, etc.

Code:

curl -X POST 'https://gribstream.com/api/v2/nbm/forecasts' \
-H "Authorization: [API_TOKEN]"" \
-d '{
    "forecastedFrom": "2024-09-10T00:00:00Z",
    "forecastedUntil": "2024-09-10T03:00:00Z",
    "minHorizon": 1,
    "maxHorizon": 3,
    "coordinates": [
        { "lat": 47.6, "lon": -122.33 }
    ],
    "variables": [
        { "name": "TMP", "level": "2 m above ground", "info": "", "alias": "temp" },
        { "name": "WIND", "level": "10 m above ground", "info": "", "alias": "wind_speed" },
        { "name": "DPT", "level": "2 m above ground", "info": "", "alias": "dew_point" }
    ]
    }'

Output:

forecasted_at,forecasted_time,lat,lon,name,dew_point,temp,wind_speed
2024-09-10T00:00:00Z,2024-09-10T01:00:00Z,47.6000,-122.3300,,288.2500,294.2700,1.6000
2024-09-10T00:00:00Z,2024-09-10T02:00:00Z,47.6000,-122.3300,,288.4000,293.4800,1.6000
2024-09-10T00:00:00Z,2024-09-10T03:00:00Z,47.6000,-122.3300,,288.2600,293.0000,1.6000
2024-09-10T01:00:00Z,2024-09-10T02:00:00Z,47.6000,-122.3300,,288.3500,293.4900,1.6000
2024-09-10T01:00:00Z,2024-09-10T03:00:00Z,47.6000,-122.3300,,288.1800,292.9800,1.6000
2024-09-10T01:00:00Z,2024-09-10T04:00:00Z,47.6000,-122.3300,,288.1900,292.2100,1.2000
2024-09-10T02:00:00Z,2024-09-10T03:00:00Z,47.6000,-122.3300,,288.1600,292.9500,1.6000
2024-09-10T02:00:00Z,2024-09-10T04:00:00Z,47.6000,-122.3300,,288.3800,292.1800,1.2000
2024-09-10T02:00:00Z,2024-09-10T05:00:00Z,47.6000,-122.3300,,287.9300,291.2800,1.2000
2024-09-10T03:00:00Z,2024-09-10T04:00:00Z,47.6000,-122.3300,,288.3300,292.0300,1.2000
2024-09-10T03:00:00Z,2024-09-10T05:00:00Z,47.6000,-122.3300,,287.9400,291.4900,1.2000
2024-09-10T03:00:00Z,2024-09-10T06:00:00Z,47.6000,-122.3300,,287.8000,290.8100,1.2000

Note: Rows are presented here sorted by forecasted_at to make the result easier to grok. Notice each model run time returned horizons 1 to 3

Please reach out for scenarios not covered in this guide. info@gribstream.com.