Lightning API · Documentation
One endpoint. Pass your API key and get back a JSON array of lightning flashes. Filter by time window and geographic bounding box. No SDK required.
All requests must include your API key in the X-API-Key header. Keys are generated from your dashboard and can be rotated at any time. Never expose your key in client-side code, proxy requests through your own backend.
Heads up: api.lightningapi.dev now also works as an API hostname, alongside api.warpulse.com. Nothing is required from you right now, both work identically and api.warpulse.com is not going away today. We plan to retire it in favor of api.lightningapi.dev in early 2027, and we will give plenty of advance notice before that happens.
curl "https://api.lightningapi.dev/v1/flashes?since_minutes=15" \
-H "X-API-Key: YOUR_API_KEY"https://api.lightningapi.dev/v1/flashesReturns an array of lightning flash events matching the given filters.
All parameters are optional. Without a bounding box, the response covers the full Americas, Atlantic, and Pacific region (including Hawaii and Alaska).
Narrow results to any rectangular region by passing all four bounding box parameters together. All four must be present, a partial set returns a 400 error. Coordinates use decimal degrees (WGS84).
# Florida curl "https://api.lightningapi.dev/v1/flashes" \ -H "X-API-Key: YOUR_API_KEY" \ -G \ -d since_minutes=15 \ -d min_lat=24.52 \ -d max_lat=31.00 \ -d min_lon=-87.63 \ -d max_lon=-80.03 # Custom box, NYC metro area curl "https://api.lightningapi.dev/v1/flashes" \ -H "X-API-Key: YOUR_API_KEY" \ -G \ -d since_minutes=30 \ -d min_lat=40.45 \ -d max_lat=41.15 \ -d min_lon=-74.30 \ -d max_lon=-73.65
Successful responses return HTTP 200 with a JSON object containing a flashes array. Each flash has four fields.
{
"flashes": [
{
"flash_id": 58097,
"lat": -5.91299,
"lon": -77.38203,
"flash_timestamp_utc": "2026-06-25T21:58:59.348063"
},
...
]
}Every numeric cap referenced above (since_minutes and limit on /v1/flashes) depends on your plan, shown below. Exceeding the rate limit returns HTTP 429; exceeding the history window or per-call limit with an explicitly-passed value returns HTTP 400.
Free
Monthly calls
per account
50,000
History window
per account
15 minutes
Limit / call
per account
500
Rate limit
per key
Non-commercial use only
Max zones
per account
1
Starter
Monthly calls
per account
250,000
History window
per account
15 minutes
Limit / call
per account
2,000
Rate limit
per key
Fair usage policy
Max zones
per account
5
Pro
Monthly calls
per account
5,000,000
History window
per account
6 hours
Limit / call
per account
20,000
Rate limit
per key
Fair usage policy
Max zones
per account
25
Ultimate
Monthly calls
per account
25,000,000
History window
per account
24 hours
Limit / call
per account
20,000
Rate limit
per key
Fair usage policy
Max zones
per account
100
Enterprise
Monthly calls
per account
100,000,000+
History window
per account
Unlimited
Limit / call
per account
20,000
Rate limit
per key
Fair usage policy
Max zones
per account
100
Monthly calls, history window, and limit per call all apply to your account as a whole — extra API keys don't add quota. Rate limit is the one that's tracked separately per key, so each key gets its own allowance.
"History window" is the maximum value allowed for since_minutes. "Limit / call" is the maximum value allowed for limit (default 2,000, itself capped to your plan's value if you don't pass one explicitly). Both silently clamp down to your plan's cap if you never touch the parameter at all; passing a value that explicitly exceeds your plan's cap returns a 400 with a message naming the exact limit.
Monthly quotas reset on your billing anniversary each month, not the calendar month. Usage is visible on your dashboard.
Quota is consumed based on how many flashes a request returns, not per request: every 100 flashes returned costs 1 unit of your monthly quota, with a minimum of 1 unit per call. A request returning 50 flashes still costs 1 unit; a request returning 5,000 flashes costs 50. The X-Quota-Cost response header on every /v1/flashes call tells you exactly what that call cost.
400Bad Request
Invalid parameter value or combination (e.g. min_lat without max_lat, limit exceeds plan cap).
401Unauthorized
Missing or invalid X-API-Key header.
429Too Many Requests
Rate limit exceeded for your plan. Back off and retry.
500Server Error
Unexpected server error. Contact support if the issue persists.
Pick a US state or region, draw a custom bounding box, or enter coordinates manually. The query updates live in your chosen language.
Free & Starter cap at 15 min. Pro caps at 6 hours, Ultimate at 24 hours, and Enterprise has no history limit.
Free caps at 500/call. Starter caps at 2,000/call. Pro, Ultimate & Enterprise cap at 20,000/call.
Bounding box (or use the map below)
Regions
US States
Generated query
curl "https://api.lightningapi.dev/v1/flashes" \
-H "X-API-Key: YOUR_API_KEY" \
-G \
-d since_minutes=15Define a zone (a center point and a radius) and get a signed webhook POST when a strike lands inside it. Delivery is near real-time and doesn't count against your monthly call quota. Manage zones via the API below, or from the dashboard, using the same X-API-Key header as /v1/flashes for API access. Zone count is capped by plan; see Max zones in the Plan Limits table above.
https://api.lightningapi.dev/developer/zonesCreate a zone. Returns webhook_secret once; store it, it is never shown again.https://api.lightningapi.dev/developer/zonesList your zones. Never includes webhook_secret.https://api.lightningapi.dev/developer/zones/{id}Delete a zone. Its alert history is deleted with it.https://api.lightningapi.dev/developer/zones/{id}/alertsRecent firings for a zone, with delivery_status. Useful for debugging a webhook endpoint that isn't receiving deliveries.curl -X POST https://api.lightningapi.dev/developer/zones \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Construction Site A",
"center_lat": 33.41,
"center_lon": -94.02,
"radius_km": 10,
"cooldown_minutes": 5,
"webhook_url": "https://your-server.example.com/lightning-webhook"
}'The first strike inside a zone fires immediately. Further strikes in that same zone are suppressed for cooldown_minutes (default 5) before it can fire again.
Every delivery includes an X-Lightning-Signature header: sha256=<hex hmac>, computed over the raw request body using your zone's webhook_secret as the HMAC key. Verify it before trusting the payload.
{
"delivery_id": 4821,
"zone_id": 123,
"zone_name": "Construction Site A",
"flash": { "lat": 33.41, "lon": -94.02, "timestamp_utc": "2026-08-04T18:22:10" },
"distance_km": 3.2
}import hashlib, hmac
def verify(secret: str, body: bytes, header: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)1stImmediate2nd+30s3rd+2min4th+10min, then marked failedRetried on any non-2xx response or timeout. Your endpoint must respond within 5 seconds; anything slower is treated as a timeout and retried on the same schedule. Use delivery_id for idempotency if you receive the same delivery more than once during a retry window.
GET /developer/zones/{id}/alerts returns each firing's delivery_status, one of pending (queued, not yet delivered), delivered (2xx received), or failed (all 4 attempts exhausted). Useful for confirming whether your endpoint is actually receiving deliveries.