Solutions · Storms API

Tropical cyclones with cones, tracks and approach alerts

Every active tropical cyclone worldwide with its position, intensity, forecast cone and wind zones. Get a webhook when a storm forms, strengthens, comes within range of your port or asset, or dissipates.

  • Port and terminal hurricane preparedness
  • Fleet and cargo exposure alerts
  • Offshore operations planning
Request
# Active systems with forecast cones, tracks and wind zones
curl "https://www.seasignals.com/v1/storms/active?geometry=false" \
  -H "Authorization: Bearer $SS_KEY"
Endpoints

Query it whenever you need it

GeoJSON responses with typed IDs, ISO 8601 times and units in every field name. Errors come back as {"error": {"code", "message"}}.

GET/v1/storms/activeActive systems with forecast cones, tracks and wind zones
GET/v1/ocean/pointExposure for a location: distance, bearing and whether it's in the cone (layers=storms)
Webhooks

Or let the events come to you

Subscribe a URL once and SeaSignals POSTs a signed JSON event whenever something changes. Checked every 30 minutes.

EVENTstorm.formedA new storm, at or above min_wind_kn
EVENTstorm.strengthenedIts category or alert level went up
EVENTstorm.approachingIt came within radius_nm of your point
EVENTstorm.dissipatedIt's no longer active

Filters

latYour point, needed for storm.approaching
lon
radius_nm1 to 1,000 nm
min_wind_knIgnore weaker systems
Create a webhook
curl -X POST https://www.seasignals.com/v1/webhooks \
  -H "Authorization: Bearer $SS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/hooks/seasignals",
  "product": "storms",
  "events": [
    "storm.formed",
    "storm.strengthened",
    "storm.approaching",
    "storm.dissipated"
  ],
  "filters": {
    "lat": 29.7,
    "lon": -95.0,
    "radius_nm": 400,
    "min_wind_kn": 34
  }
}'
POST to your URL
{
  "id": "evt_3kV9q2mXw8rT1yLp0aZc4nB7",
  "type": "storm.approaching",
  "created_at": "2026-10-29T09:00:12Z",
  "webhook": "webhook:42",
  "data": {
    "type": "Feature",
    "id": "storm:1001234",
    "geometry": {
      "type": "Point",
      "coordinates": [
        -90.4,
        26.1
      ]
    },
    "properties": {
      "name": "Vance",
      "classification": "Hurricane",
      "category": 2,
      "max_wind_kn": 90,
      "movement_dir_deg": 315,
      "movement_speed_kn": 11,
      "distance_nm": 318.6,
      "bearing_deg": 128
    }
  }
}
Delivery

Signed, retried, logged

  • Signed: every request carries SeaSignals-Signature, an HMAC-SHA256 of the timestamp and body with your webhook secret.
  • Retried: anything but a 2xx within 10 seconds is retried after 1 min, 5 min, 30 min, 2 h and 6 h.
  • Logged: GET /v1/webhooks/{id} shows recent deliveries, and POST /v1/webhooks/{id}/test sends a test event.
  • Safe to retry: use the event id to ignore a delivery you've already handled.
// header: SeaSignals-Signature: t=1761729600,v1=5f2b…
const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
const expected = crypto.createHmac("sha256", process.env.SS_WEBHOOK_SECRET)
  .update(`${t}.${rawBody}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
  && Date.now() / 1000 - Number(t) < 300;

Try the Storms API free

The free trial includes every API and up to 5 webhooks, 1,000 requests a day and 14 days of history.