Map layers and tiles
Weather tiles are value-encoded PNGs: each pixel carries the scalar, not a colour. You colour them on the client from the layer’s published stops, so a legend and the map can never disagree, and one tile set serves every palette and unit. Tiles are run-stamped and immutable. 0.2 credits each.
Catalogue
Section titled “Catalogue”GET /v1/layersFree. Every (model, var) layer with its current run, the valid hours that are published (including the retained extended run’s tail), zoom ceiling, bounds, encode range, colour stops and min_fxx.
{ "tilerev": 3, "encoding": "value: R=G=B=(v-lo)/(hi-lo)*254, alpha 0 = nodata", "layers": [ { "id": "hrrr/toplift", "model": "hrrr", "var": "toplift", "units": "m", "encode": [0, 6000], "min_fxx": 1, "stops": [[0, 72, 60, 90, 0], [1219, 150, 70, 145, 255], "…"], "run": "2026-09-19T12", "valid": ["2026-09-19T12", "2026-09-19T13", "…"], "extended_run": "2026-09-19T06", "minzoom": 0, "maxzoom": 6, "bounds": [-125, 24, -66.5, 49.5], "tilejson": "https://api.vertexmaps.com/v1/layers/hrrr/toplift/tilejson.json?valid={valid}", "tiles": "https://api.vertexmaps.com/v1/tiles/hrrr/{run}/toplift/f{FF}/{z}/{x}/{y}.png", "attribution": "NOAA HRRR via Vertex API" } ]}TileJSON
Section titled “TileJSON”GET /v1/layers/{model}/{var}/tilejson.json?valid=2026-09-19T21Free. A TileJSON 3.0 document for one layer at one valid hour, with the run and forecast hour resolved for you. If the key arrived as ?apikey=, the tile template carries it; otherwise send Authorization: Bearer with tile requests (most SDKs can’t) or append ?apikey= yourself.
{ "tilejson": "3.0.0", "tiles": ["https://api.vertexmaps.com/v1/tiles/hrrr/2026-09-19T12/toplift/f09/{z}/{x}/{y}.png?apikey=vtx_live_…"], "minzoom": 0, "maxzoom": 6, "bounds": [-125, 24, -66.5, 49.5], "attribution": "NOAA HRRR via Vertex API", "model": "hrrr", "layer": "toplift", "run": "2026-09-19T12", "fxx": 9, "valid": "2026-09-19T21", "units": "m", "encode": [0, 6000], "stops": [ … ]}Set your raster source’s maxzoom from the document. Above it, tiles are 204 and the SDK oversamples the last zoom, which is the intended look for 3 km data.
Colouring tiles
Section titled “Colouring tiles”Decode with the encode range, then map value to colour with the stops. Stops are [value, r, g, b, a] rows, sorted by value.
Mapbox GL JS v3 supports this natively:
map.addSource("toplift", { type: "raster", tiles: tj.tiles, tileSize: 256, maxzoom: tj.maxzoom });const [lo, hi] = tj.encode;map.addLayer({ id: "toplift", type: "raster", source: "toplift", paint: { "raster-color-mix": [((hi - lo) * 255) / 254, 0, 0, lo], "raster-color-range": [lo, hi], "raster-color": ["interpolate", ["linear"], ["raster-value"], ...tj.stops.flatMap(([v, r, g, b, a]) => [v, `rgba(${r},${g},${b},${a / 255})`])], "raster-opacity": 0.7, },});MapLibre, Leaflet, deck.gl, QGIS: decode in a tile-load hook or shader: value = lo + (R / 254) * (hi - lo), transparent where alpha is 0, then look up the stops. Complete examples, with animation, legends, overlays and the static layers: Mapbox GL JS, MapLibre GL JS (a canvas protocol), Leaflet (a canvas tile layer with a value readout).
Layers
Section titled “Layers”| var | Units | Models | Notes |
|---|---|---|---|
temp |
°C | all | 2 m temperature |
cloud, cloudlow, cloudmid, cloudhigh |
% | all (decks: hrrr, rrfs, nam, gfs) | Cloud cover, total and by deck |
clouddecks |
packed | hrrr, rrfs, nam, gfs | R = low, G = mid, B = high deck cover in one tile |
precip1h, precip3h |
mm | all | Accumulations; min_fxx 1 and 3 |
snow6h … snow48h |
cm | hrrr, rrfs | New snow windows |
snowdepth |
m | hrrr, rrfs, nam, gfs | |
windspeed, gust |
m/s | all | 10 m |
wstar |
m/s | hrrr, rrfs, nam, gfs | Updraft velocity |
toplift, cubase |
m MSL | hrrr, rrfs, nam, gfs | Top of usable lift, cumulus base; transparent where none |
cudepth, odpot, spreadout |
m | hrrr, rrfs, nam, gfs | Cumulus depth, overdevelopment potential, spread-out |
cape |
J/kg | all | |
conv |
m/s | hrrr, rrfs, nam | Low-level convergence (3 km grids only) |
refl |
dBZ | hrrr, rrfs, nam | Simulated composite reflectivity |
smoke, aqi |
µg/m³, AQI | hrrr | Near-surface smoke and its AQI |
Tiles directly
Section titled “Tiles directly”GET /v1/tiles/{model}/{run}/{var}/f{FF}/{z}/{x}/{y}.pngrun is YYYY-MM-DDTHH (UTC), FF the two- or three-digit forecast hour. Use the catalogue or /v1/meta.json to map a valid time to a run and hour; TileJSON does it for you.
GET /v1/meta.json is the raw discovery document the catalogue is built from: per-model runs, valid hours, zoom ceilings, the layers table with encode ranges and stops, and the metadata for overlays. Free; cached for 60 seconds.
Overlays
Section titled “Overlays”Vector companions to the rasters, one credit each, run-stamped and immutable:
| Endpoint | Content |
|---|---|
/v1/barbs/{model}/{run}/f{FF}/{level}.png |
Wind field as a UV-encoded PNG (u in R, v in G, ±60 m/s) for drawing barbs or particles. Levels: sfc, 1000ft … 18000ft. Grid bounds in meta.barbs. |
/v1/barbs/{model}/{run}/f{FF}/{level}.geojson |
The same wind field as a ~15 km point grid with speed_kn and direction_deg. |
/v1/isobars/{model}/{run}/f{FF}.geojson |
Mean-sea-level pressure contours. |
/v1/thunder/{model}/{run}/f{FF}.geojson |
Forecast lightning-potential points from HRRR with tiers 1–3 (forecast, not observed strikes). |
/v1/precipbands/{model}/{run}/{var}/f{FF}.geojson |
Precipitation as banded polygons for precip1h / precip3h, for hatched fills. |
GET /v1/radar/index.json (free) lists MRMS reflectivity frames at 5-minute steps for the trailing two hours plus a nowcast to +60 minutes, rebuilt every two minutes. Each frame is a tile set at /v1/radar/{frame}/{z}/{x}/{y}.png, value-encoded in dBZ with the refl stops.
Caching
Section titled “Caching”Weather and radar tiles are immutable and carry cache-control: public, max-age=31536000, immutable; static layers carry a day. Cache them. Repeat views from your cache are free.