api.weather.gov gridpoints: validTime is an interval, values are Celsius, and units=us is rejected Checked 2026-09-08 · Health, environment and transport datasets The raw /gridpoints endpoint returns each variable as a run-length list: every entry is {validTime, value} where validTime is an ISO-8601 interval like "2026-09-07T20:00:00+00:00/PT3H", so one entry can stand for three hours. Temperature is degC there whatever your locale, ?units=us is rejected with HTTP 400, and the first entry can be in the past. The /gridpoints/.../forecast child endpoint is the one that gives Fahrenheit. What we saw Temperature on the raw gridpoint is wmoUnit:degC and entries carry variable durations. Source: https://api.weather.gov/gridpoints/TOP/32,81 (properties.temperature.uom and .values, 2026-09-08). uom: wmoUnit:degC {'validTime': '2026-09-07T18:00:00+00:00/PT1H', 'value': 33.888888888888886} {'validTime': '2026-09-07T19:00:00+00:00/PT1H', 'value': 34.44444444444444} {'validTime': '2026-09-07T20:00:00+00:00/PT3H', 'value': 36.666666666666664} {'validTime': '2026-09-07T23:00:00+00:00/PT1H', 'value': 35.55555555555556} 143 entries cover 175 hours, so treating the list as hourly undercounts the horizon by a fifth. Source: https://api.weather.gov/gridpoints/TOP/32,81 (properties.temperature.values, count and summed durations, 2026-09-08). n values: 143 durations: [('PT1H', 122), ('PT3H', 11), ('PT2H', 10)] sum hours 175 The array starts before the moment you fetch it: properties.validTimes says the block began 2026-09-07T18:00Z, fetched on 2026-09-08. values[0] is not "now". Source: https://api.weather.gov/gridpoints/TOP/32,81 (properties.updateTime and .validTimes, 2026-09-08). updateTime 2026-09-08T00:41:26+00:00 validTimes 2026-09-07T18:00:00+00:00/P7DT7H first 2026-09-07T18:00:00+00:00/PT1H last 2026-09-15T00:00:00+00:00/PT1H ?units=us is not accepted on the raw gridpoint — HTTP 400 naming the parameter. Source: https://api.weather.gov/gridpoints/TOP/32,81?units=us (parameterErrors, 2026-09-08). { "correlationId": "582efd95", "parameterErrors": [ { "parameter": "query.units", "message": "Query parameter \"units\" is not recognized" } ], "title": "Bad Request", "type": "https://api.weather.gov/problems/BadRequest", "status": 400 } The /forecast child of the same gridpoint defaults to US units and reports temperature as an integer with temperatureUnit F. Source: https://api.weather.gov/gridpoints/TOP/32,81/forecast (properties.units and properties.periods[0], 2026-09-08). units us {'name': 'Overnight', 'temperature': 76, 'temperatureUnit': 'F', 'probabilityOfPrecipitation': {'unitCode': 'wmoUnit:percent', 'value': 1}} Other variables in the same document carry their own units — precipitation is millimetres, probability is percent — so there is no single unit for the payload. Source: https://api.weather.gov/gridpoints/TOP/32,81 (properties.quantitativePrecipitation.uom and .probabilityOfPrecipitation.uom, 2026-09-08). probabilityOfPrecipitation uom: wmoUnit:percent quantitativePrecipitation uom: wmoUnit:mm A request with no User-Agent is refused with HTTP 403 and an HTML page, so the header is mandatory here. Source: https://api.weather.gov/points/39.7456,-97.0892 (response with User-Agent suppressed, 2026-09-08). http=403 Access Denied

Access Denied

The command UA='opendatanotes.org maintainer@opendatanotes.org'; curl -sS -A "$UA" -o grid.json 'https://api.weather.gov/gridpoints/TOP/32,81'; python3 -c "import json,collections;d=json.load(open('grid.json'))['properties'];t=d['temperature'];print(t['uom']);[print(v) for v in t['values'][:4]];print('n',len(t['values']));print(collections.Counter(v['validTime'].split('/')[1] for v in t['values']).most_common())" uom: wmoUnit:degC {'validTime': '2026-09-07T18:00:00+00:00/PT1H', 'value': 33.888888888888886} {'validTime': '2026-09-07T19:00:00+00:00/PT1H', 'value': 34.44444444444444} {'validTime': '2026-09-07T20:00:00+00:00/PT3H', 'value': 36.666666666666664} {'validTime': '2026-09-07T23:00:00+00:00/PT1H', 'value': 35.55555555555556} n values: 143 durations: [('PT1H', 122), ('PT3H', 11), ('PT2H', 10)] Checked 2026-09-08. curl -sS -A "$UA" -o gridus.json -w 'units=us http=%{http_code}\n' 'https://api.weather.gov/gridpoints/TOP/32,81?units=us'; cat gridus.json units=us http=400 { "correlationId": "582efd95", "parameterErrors": [ { "parameter": "query.units", "message": "Query parameter \"units\" is not recognized" } ], "title": "Bad Request", "status": 400 } Checked 2026-09-08. curl -sS -A "$UA" -o fc.json 'https://api.weather.gov/gridpoints/TOP/32,81/forecast'; python3 -c "import json;p=json.load(open('fc.json'))['properties'];print('units',p.get('units'));x=p['periods'][0];print({k:x[k] for k in ('name','temperature','temperatureUnit','probabilityOfPrecipitation')})" units us {'name': 'Overnight', 'temperature': 76, 'temperatureUnit': 'F', 'probabilityOfPrecipitation': {'unitCode': 'wmoUnit:percent', 'value': 1}} Checked 2026-09-08. curl -sS -H 'User-Agent:' -o nua.json -w 'no UA http=%{http_code}\n' 'https://api.weather.gov/points/39.7456,-97.0892'; head -c 100 nua.json no UA http=403 Access Denied

Access Denied

Checked 2026-09-08. endpoint temperature unit time field entries /gridpoints/TOP/32,81 wmoUnit:degC validTime, an ISO-8601 interval (PT1H, PT2H, PT3H) 143 entries covering 175 hours /gridpoints/TOP/32,81/forecast F (properties.units = us) startTime and endTime named periods /gridpoints/TOP/32,81?units=us - - HTTP 400, parameter not recognized Limits - One gridpoint, one fetch. The mix of PT1H/PT2H/PT3H runs is a property of that forecast issuance and will differ elsewhere and later. - The documented behaviour where /points rejects coordinates with more than four decimal places did not fire: /points/39.745600,-97.089200 returned HTTP 200, not a redirect. I did not chase why. - I did not check whether validTime intervals can ever overlap or leave gaps; here they summed to 175 hours against a stated block of P7DT7H, which is 175 hours, so this one was contiguous. Open question Are the run-length durations always whole hours? A PT30M or a P1D entry would break code that parses the duration with a fixed pattern. Know something this page does not say? Send it with one GET: https://opendatanotes.org/c?kind=correction&page=nws-gridpoints-validtime-intervals&text=… — no account needed. I read everything that comes in, and nothing sent here gets published. Everything here was run from one machine on the date shown.