API Reference

Documentation

Single endpoint. Three risk dimensions. Any US coordinate. All responses are normalized to the same 0–100 scale so you can display, compare, or alert on them with a single code path.

01

Quick start

Make your first request in under a minute.

1

Get a free API key — no credit card required.

2

Make a request:

Shell
curl "https://api.gravelo.io/v1/risk?lat=40.71&lng=-74.00" \
  -H "Authorization: Bearer pk_live_your_key_here"
3

Read .flood.score, .air_quality.aqi, and .river.score — all on the same 0–100 scale.

02

Authentication

Pass your API key as a Bearer token in the Authorization header of every request.

HTTP header
Authorization: Bearer pk_live_your_key_here

Keys prefixed pk_live_ are production keys. Never commit keys to source control — use environment variables.

03GET

/v1/risk

All plans1 call per request

Returns flood, air quality, and river gauge risk scores for a US coordinate. Responses are cached up to 1 hour per location.

Request
curl "https://api.gravelo.io/v1/risk?lat=40.71&lng=-74.00" \
  -H "Authorization: Bearer pk_live_your_key_here"
04

Parameters

All parameters are passed as query string values.

NameTypeRequiredDescription
latfloatrequiredLatitude in decimal degrees, WGS84. Range: −90 to 90.
lngfloatrequiredLongitude in decimal degrees, WGS84. Range: −180 to 180.
sourcesstringoptionalComma-separated subset: flood, air, river. Omit for all three.
05

Response schema

All successful responses return 200 OK with Content-Type: application/json.

200 OK · application/json
{
  "location": { "lat": 40.71, "lng": -74.0 },
  "flood": {
    "fema_zone":    "X",
    "zone_subtype": null,
    "score":        5,
    "label":        "Minimal",
    "source":       "FEMA NFHL"
  },
  "air_quality": {
    "aqi":               41,
    "primary_pollutant": "O3",
    "category":          "Good",
    "score":             5,
    "label":             "Good",
    "source":            "AirNow",
    "preliminary":       true
  },
  "river": {
    "nearest_gauge":  "RICHMOND CREEK AT LIGHTHOUSE AVE",
    "site_no":        "01376534",
    "gage_height_ft": 1.09,
    "flood_stage_ft": null,
    "flood_stage_pct": null,
    "score":          10,
    "label":          "Minimal",
    "source":         "USGS"
  },
  "updated_at": "2026-03-16T15:59:01Z"
}
FieldTypeDescription
location.latfloatEchoed latitude.
location.lngfloatEchoed longitude.
flood.fema_zonestringFEMA flood zone designation (e.g. AE, X, AO).
flood.zone_subtypestring | nullFEMA zone subtype when present.
flood.scoreint 0–100Normalized flood risk score.
flood.labelstringHuman-readable risk label.
flood.sourcestringAlways "FEMA NFHL".
air_quality.aqiintUS AQI value (0–500).
air_quality.primary_pollutantstringDominant pollutant code (PM2.5, O3, NO2 …).
air_quality.categorystringEPA AQI category (Good, Moderate, Unhealthy …).
air_quality.scoreint 0–100Normalized air quality risk score.
air_quality.preliminarybooleantrue when data is not yet QA-verified by EPA.
river.nearest_gaugestringName of the closest USGS streamflow gauge.
river.site_nostringUSGS site number for the gauge.
river.gage_height_ftfloat | nullCurrent gage height in feet.
river.flood_stage_ftfloat | nullOfficial flood stage threshold in feet, if published.
river.flood_stage_pctfloat | nullCurrent height as % of flood stage. null if threshold unknown.
river.scoreint 0–100Normalized river flood risk score.
updated_atISO 8601Timestamp of the most recently fetched data source.
06POST

/v1/risk/batch

Developer+N calls per request (one per location)

Look up risk data for up to 50 coordinates in a single request. Each location counts as one call against your monthly quota. Ideal for property portfolio analysis, insurance underwriting, and bulk enrichment pipelines.

Request
curl -X POST "https://api.gravelo.io/v1/risk/batch" \
  -H "Authorization: Bearer pk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"locations":[{"lat":40.71,"lng":-74.00},{"lat":34.05,"lng":-118.24}]}'
Request body
{
  "locations": [
    { "lat": 40.71, "lng": -74.00 },
    { "lat": 34.05, "lng": -118.24 },
    { "lat": 29.76, "lng": -95.37 }
  ]
}
200 OK
{
  "results": [
    {
      "location":   { "lat": 40.71, "lng": -74.0 },
      "flood":      { "fema_zone": "X", "score": 5, "label": "Minimal", ... },
      "air_quality": { "aqi": 41, "score": 5, "label": "Good", ... },
      "river":      { "score": 10, "label": "Minimal", ... },
      "updated_at": "2026-03-16T15:59:01Z"
    },
    { ... }
  ],
  "count":         2,
  "calls_charged": 2
}
Response fieldTypeDescription
resultsarrayOrdered array of risk results, one per input location.
results[].errorstring?Set if a single coordinate failed; other results still returned.
countintNumber of locations processed.
calls_chargedintCalls deducted from your monthly quota (equal to count).
07GET

/v1/flood/zone

All plans1 call per request

FEMA flood zone only — no air quality or river data. Faster and cheaper for mortgage, title, and real estate workflows that only need flood zone status.

Request
curl "https://api.gravelo.io/v1/flood/zone?lat=40.71&lng=-74.00" \
  -H "Authorization: Bearer pk_live_your_key_here"
ParamTypeRequiredDescription
latfloatrequiredLatitude in decimal degrees, WGS84. Range: −90 to 90.
lngfloatrequiredLongitude in decimal degrees, WGS84. Range: −180 to 180.
200 OK
{
  "location":    { "lat": 40.71, "lng": -74.0 },
  "fema_zone":   "X",
  "zone_subtype": null,
  "county_fips": "36061",
  "risk_score":  5,
  "label":       "Minimal",
  "source":      "FEMA NFHL"
}
FieldTypeDescription
locationobjectEchoed lat/lng input.
fema_zonestringFEMA flood zone code, e.g. AE, X, VE.
zone_subtypestring | nullZone subtype when present, e.g. "0.2 PCT ANNUAL CHANCE".
county_fipsstring | null5-digit FIPS code for the county.
risk_scoreint 0–100Normalized flood risk score.
labelstringHuman-readable risk label.
sourcestringAlways "FEMA NFHL".
08GET

/v1/sources/status

All plansDoes not count against quota

Returns the last-fetched timestamp, reading count, and staleness flag for every upstream data source. Use it to display freshness badges or alert when data is unexpectedly old.

Request
curl "https://api.gravelo.io/v1/sources/status" \
  -H "Authorization: Bearer pk_live_your_key_here"
200 OK
{
  "sources": [
    {
      "source":        "airnow",
      "hazard_type":   "air_quality",
      "last_updated":  "2026-03-16T14:00:00Z",
      "reading_count": 4821,
      "age_hours":     1.9,
      "stale":         false
    },
    { "source": "usgs", "hazard_type": "river", ... }
  ],
  "fema_last_updated": "2026-01-03T08:00:00Z",
  "fema_zone_count":  2847193,
  "checked_at":       "2026-03-16T15:59:01Z"
}
FieldTypeDescription
sourcesarrayOne entry per source/hazard combination in the database.
sources[].sourcestringSource identifier, e.g. "airnow", "usgs".
sources[].hazard_typestringHazard category, e.g. "air_quality", "river".
sources[].last_updatedISO 8601Timestamp of the most recent reading for this source.
sources[].reading_countintTotal readings stored for this source/hazard pair.
sources[].age_hoursfloatHours since last_updated.
sources[].stalebooleantrue if age_hours > 24 or last_updated is null.
fema_last_updatedISO 8601Timestamp of the most recent FEMA flood zone row.
fema_zone_countintTotal FEMA flood zone polygons loaded.
checked_atISO 8601Server time when this response was generated.
09

Score scale

All five hazard types use the same 0–100 scale so you can render a unified risk indicator or fire a single alert threshold. Every hazard also returns a score_basis string explaining exactly what drove the score — useful for audits and underwriting workflows.

0–15MinimalLow probability of impact. No action required.
16–40WatchElevated but not immediately hazardous.
41–69ModerateMeaningful risk. Review mitigations.
70–89HighSignificant risk. Action recommended.
90–100ExtremeSevere hazard. Immediate attention required.

Per-hazard scoring methodology

HazardInputScoring methodscore_basis example
floodFEMA flood zone letterZone → fixed score (VE=95, AE/AH/AO=80, A=70, X 500-yr=20, X=5)"FEMA zone AE"
air_qualityEPA AQI (0–500)AQI linearly mapped to 0–100. AQI 0 = score 0, AQI 300+ = score 100."AQI 41 · O3"
riverUSGS gage height vs. flood stageflood_stage_pct mapped to score. 0% = 0, 100% = 70, 150%+ = 100."62% of flood stage"
wildfireFEMA NRI census tract scoreDirect passthrough of FEMA NRI wildfire risk score (0–100)."FEMA NRI score 82 (Very High)"
earthquakeUSGS PGA (g), 2%/50yrPiecewise log-calibrated to US hazard distribution. 0.04g=15, 0.3g=50, 0.6g=70, 1.5g=90."PGA 0.62g (2%/50yr, USGS NSHM)"

Scores are independently derived per hazard and should not be summed directly — use them as individual risk signals or weight them by your own model.

10

Error codes

Errors always return JSON with an detail field containing a human-readable message.

Error shape
{ "detail": "Monthly call limit reached. Upgrade your plan at gravelo.io/pricing" }
StatusMeaningDescription
400Bad Requestlat or lng is missing or out of range (±90/±180).
401UnauthorizedAPI key is missing, invalid, or inactive.
403ForbiddenMonthly call limit reached. Upgrade your plan.
404Not FoundNo data available for that coordinate (outside US coverage).
429Too Many RequestsBurst rate limit exceeded. Retry after the X-RateLimit-Reset time.
500Internal Server ErrorUpstream data source unavailable. Retry after 60 s.
11

Rate limits

Limits are per API key, per calendar month. Every response includes current usage headers.

Response headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 84
X-RateLimit-Reset: 1748736000

Free

100 / month

Developer

5,000 / month

Pro

50,000 / month

Burst limit: 10 requests / second per key. Cached responses do not count against your monthly quota.

12

Data sources

Gravelo aggregates authoritative US government data. Risk scores are Gravelo's own normalized derivation and do not constitute official agency guidance.

floodFEMA National Flood Hazard Layer
FEMA NFHL

Official flood zone designations updated as FEMA issues new FIRMs. Coverage: contiguous US. https://msc.fema.gov/portal/home

air_qualityEPA AirNow
AirNow

Preliminary real-time AQI data from federal, state, local, and tribal monitoring agencies. Not for regulatory use. https://www.airnow.gov

riverUSGS National Water Information System
USGS NWIS

Real-time gage height and streamflow. Provisional data subject to revision. https://waterdata.usgs.gov

All data provided "as-is" for informational purposes only. Not intended to support regulatory decisions, establish legal liability, or substitute for professional risk assessment.