Developer · public API

Build on Hail GPS.

REST endpoints over every hail cell Hail GPS has ingested, plus the live radar frames and SPC hail outlooks behind the map. Proper GeoJSON out. No auth required for anything on this page.

Base URLhttps://hail-scout-production.up.railway.app

Endpoints

Six endpoints, all public.

Storm cells, address history, aggregate stats, forecast outlooks, and the radar loop — the same data the product renders.

GET/v1/stormsList storm cells in a bounding box + date window

Query parameters

  • bboxstringWGS84: minlon,minlat,maxlon,maxlate.g. -105,30,-90,42
  • fromISO dateStart of window (inclusive)e.g. 2026-04-01
  • toISO dateEnd of window (inclusive)e.g. 2026-05-13
  • limit?intMax rows. 1-200.e.g. 50
  • include?stringComma-separated extras. "swaths" embeds the per-cell hail polygons.e.g. swaths
  • simplify?floatGeometry simplification tolerance (degrees) when include=swaths. 0 = full precision.e.g. 0.02
  • source?stringFilter pipeline source: 'MRMS' or 'NEXRAD'.e.g. MRMS
  • min_size?floatDrop cells with peak hail < this size (inches).e.g. 1.0
  • order?string'recent' (default) or 'peak' (biggest first).e.g. peak

cURL

curl "https://hail-scout-production.up.railway.app/v1/storms?bbox=-105,30,-90,42&from=2026-04-01&to=2026-05-13&limit=10&order=peak"

Response

{
  "storms": [
    {
      "id": "storm_5pYhBb3LZqq0cA",
      "start_time": "2026-04-12T11:00:00Z",
      "end_time": "2026-04-12T11:00:00Z",
      "max_hail_size_in": 2.5,
      "source": "MRMS",
      "centroid": {
        "type": "Point",
        "coordinates": [-97.95, 37.79]
      },
      "bbox": {
        "type": "Polygon",
        "coordinates": [[[ ... ]]]
      }
    }
  ],
  "cursor": null,
  "total": 1
}
GET/v1/storms/at-pointWhat hit this exact address? Storms whose swaths contain the point.

Query parameters

  • latfloatLatitude (WGS84). -90 to 90.e.g. 32.78
  • lngfloatLongitude (WGS84). -180 to 180.e.g. -96.80
  • from?ISO dateWindow start. Optional.e.g. 2025-05-13
  • to?ISO dateWindow end. Optional.e.g. 2026-05-13
  • limit?intMax hits. 1-200.e.g. 20

cURL

curl "https://hail-scout-production.up.railway.app/v1/storms/at-point?lat=32.78&lng=-96.80"

Response

{
  "lat": 32.78,
  "lng": -96.8,
  "hits": [
    {
      "id": "storm_xxx",
      "start_time": "2026-04-12T11:00:00Z",
      "end_time": "2026-04-12T11:00:00Z",
      "max_hail_size_in": 2.5,
      "source": "MRMS",
      "category_at_point": "2.5"
    }
  ],
  "total": 1
}
GET/v1/storms/{storm_id}Full storm detail with every hail swath as GeoJSON MultiPolygon

cURL

curl "https://hail-scout-production.up.railway.app/v1/storms/storm_5pYhBb3LZqq0cA"

Response

{
  "id": "storm_5pYhBb3LZqq0cA",
  "start_time": "2026-04-12T11:00:00Z",
  "end_time": "2026-04-12T11:00:00Z",
  "max_hail_size_in": 2.5,
  "source": "MRMS",
  "centroid": { "type": "Point", "coordinates": [-97.95, 37.79] },
  "bbox":     { "type": "Polygon", "coordinates": [[[ ... ]]] },
  "swaths": [
    {
      "id": "swath_yyy",
      "hail_size_category": "1.5",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [[[[ ... ]]]]
      },
      "updated_at": "2026-04-12T11:00:00Z"
    }
  ]
}
GET/v1/storms/statsAggregate counts over the whole storms table

cURL

curl "https://hail-scout-production.up.railway.app/v1/storms/stats"

Response

{
  "total_cells": 99110,
  "cells_last_24h": 122,
  "cells_last_7d": 1246,
  "cells_last_30d": 5628,
  "peak_hail_in": 7.0,
  "earliest": "2021-01-01T00:00:20Z",
  "latest":   "2026-08-01T06:50:00Z",
  "sources": { "SPC-LSR": 47443, "NEXRAD": 35379, "MRMS": 16288 }
}
GET/v1/outlook/hailNewSPC hail-probability contours for a forecast day, as GeoJSON

Query parameters

  • day?intForecast day: 1 = today, 2 = tomorrow, 3 = the day after. Default 1.e.g. 1
  • kind?string'hail' for any severe hail, 'sighail' for the significant (2in+) subset. Omit for both.e.g. hail
  • include_expired?boolAlso return outlook periods that have already ended. Default false.e.g. false

cURL

curl "https://hail-scout-production.up.railway.app/v1/outlook/hail?day=1"

Response

{
  "outlooks": [
    {
      "id": "outlook_xxx",
      "day": 1,
      "kind": "hail",
      "probability": 0.15,
      "label": "15%",
      "valid_from": "2026-08-01T12:00:00Z",
      "valid_to": "2026-08-02T12:00:00Z",
      "issued_at": "2026-08-01T12:31:00Z",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [[[[ ... ]]]]
      }
    }
  ]
}
GET/v1/radar/framesNewNewest-first radar frames for one product — image metadata + a PNG URL each

Query parameters

  • product?string'mesh' (hail size), 'posh' (hail likely), or 'reflectivity' (where the storm is). Default 'mesh'.e.g. mesh
  • limit?intHow many frames, newest first. 1-60; frames land ~every 2 minutes, so 12 ≈ 24 minutes of loop.e.g. 12

cURL

curl "https://hail-scout-production.up.railway.app/v1/radar/frames?product=mesh&limit=12"

Response

{
  "frames": [
    {
      "id": "mesh_20260801T073843Z",
      "product": "mesh",
      "valid_time": "2026-08-01T07:38:43Z",
      "bounds": {
        "min_lat": 20.0, "min_lng": -130.0,
        "max_lat": 55.0, "max_lng": -60.0
      },
      "width": 1750,
      "height": 875,
      "peak_value": 0.63,
      "url": "/v1/radar/frames/mesh_20260801T073843Z.png"
    }
  ]
}

Notes

Things to know

  • Sort order: default is start_time DESC (most recent first). Pass ?order=peak to sort by peak hail size for "biggest events" views.
  • Geometry payload: swaths can be huge. Use ?simplify=0.02 (~2 km tolerance) for map rendering; drop to 0 for full precision in analytics.
  • Source field: MRMS is the 1 km CONUS-wide radar pipeline, NEXRAD the sub-km single-radar pipeline, and SPC-LSR ground hail reports. Same schema, different upstream.
  • Radar frame PNGs: a frame id is immutable — the PNG at its url is cached forever and answers 304 to a matching ETag, so a looping client re-fetches nothing.
  • Outlooks on quiet days: a day with no hail forecast legitimately returns an empty outlooks list — never a placeholder shape. Only the newest SPC issuance is returned per kind.
  • Rate limits: none published right now. Be reasonable — we run on a shared instance.
  • Auth: none for the endpoints above. Customer-data endpoints (alerts, markers, contacts) require an authenticated session and are not documented here.

Need authenticated endpoints or higher quotas?

Request access — accounts get tokens for the customer-data endpoints: alerts, monitored addresses, exports.