API · v1

RoofTap Enrichment API

One JSON call. Roof + property + storm data on every address. Same shape every CRM. Pay-as-you-go, never billed for bad reads.

Quickstart

Activate a key in 60 seconds at /integrations/signup. You'll see the key once on the success page, copy it before closing the tab. Every key is prefixed with rt_live_.

curl -X POST https://www.rooftap.app/api/v1/enrich \
  -H "X-API-Key: rt_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{ "address": "5701 W Loma Ln, Glendale, AZ 85302" }'

Authentication

Every request must include the X-API-Key header. Keys are tied to one billing account. Treat them like passwords: do not embed in client-side JavaScript or commit to git.

Lost your key? Email support@rooftap.appfrom the address on file and we'll rotate it.

Tiers - one API, free & paid

Your key's tier decides which fields return. Free keys get the zero-cost layers: storm history, FEMA hazard risk, Census neighborhood, and areactivation flag (when you pass lead_date). Paid keys ($3.95/record, sliding to $1.95 at volume) get everything in free plusthe real-time roof + property record, roof area, facets & pitch, edge measurements, material takeoff, cost estimate, complexity, pool/garage flags, owner & property details, and solar. Premium fields are simply omitted on the free tier; upgrade and they appear with no code change (same key). Every measurementcarries a confidence score, and you're never billed for a low-confidence read. The $3.95/record rate applies only to calls that request a premium layer — a storm-only call (no roof / property / solar / imagery) is free on a paid key too.

Storm-only data

Every enrich response carries a storms block. By default it's just the last event storms.last_storm (date, type, hail size, wind, distance) plus the derived storms.claim_eligible_window. That's the answer to "when did the last storm hit this address, how big, and is the claim window still open" in one cheap call. The window we search is 2 years, which matches the ~24-month insurance claim window — older events aren't actionable.

Need the full history? Pass include: ["storm_history"] and the block expands to the complete 2-year event list (events[], newest first) plus max_hail_inches, max_wind_mph, lookback_years, and radius_miles.

// DEFAULT — last event only
POST /v1/enrich
{ "address": "5701 W Loma Ln, Glendale, AZ 85302" }

"storms": {
  "last_storm": {
    "date": "2025-09-18", "type": "hail",
    "hail_in": 1.75, "wind_mph": null, "distance_miles": 2.5
  },
  "claim_eligible_window": {
    "event_date": "2025-09-18", "expires": "2027-09-18", "days_remaining": 463
  }
}

// OPT IN — full 2-year history
POST /v1/enrich
{ "address": "5701 W Loma Ln, Glendale, AZ 85302",
  "include": ["storm_history"] }

"storms": {
  "last_storm":            { ... },
  "claim_eligible_window": { ... },
  "events": [
    { "noaa_event_id": "...", "event_type": "Hail", "event_date": "2025-09-18",
      "hail_size_inches": 1.75, "wind_speed_mph": null, "city": "Glendale",
      "state_abbr": "AZ", "distance_miles": 2.5, "damage_description": null }
  ],
  "max_hail_inches": 1.75, "max_wind_mph": 72,
  "lookback_years": 2, "radius_miles": 10
}
Storm-only calls are free — on any key. A request that asks for no premium layer (no roof, property, solar, or imagery) — e.g. "include": ["storms"] — is served as a free call: no roof measurement runs and it is never billed, even on a paid key. You get back the zero-cost layers (storms, FEMA risk, Census neighborhood, and a reactivation flag when you pass lead_date), with billable: false. The moment you add a premium layer, the call runs the full measurement and bills the per-record rate.

Two more ways to pull storm data at no charge:

  • Single address — request storm-only. As above: any key, include: ["storms"] (optionally with storm_history), unbilled. Premium roof/property/solar fields are simply omitted.
  • A list of addresses — use bulk reactivation. Screen an aged lead list against NOAA storm history and get back the homeowners worth a call today. See Bulk reactivation.

POST /v1/enrich

The primary endpoint. Returns the full enrichment payload synchronously. Cold call latency (first time we see an address) is typically 4-7 seconds, Solar API + property + storm history fetched in parallel. Cached addresses (same parcel called twice within the 7-day cache TTL) return sub-second. If you need to keep enrichment off your hot path, use the prewarm endpoint.

Request

FieldTypeDescription
addressstring · requiredFree-form US address. Examples: "123 Main St, Austin, TX 78701", "5701 W Loma Ln Glendale AZ".
lead_idstringYour internal id for the lead. Echoed back in the response so you can correlate without holding state.
lead_datestring (YYYY-MM-DD)Date the lead was generated. When present, the response adds a reactivation flag, true if a qualifying storm hit since that date.
owner_match_namestringName on the lead form. We compare against deed-of-record and return property.owner_match.
includestring[]Narrow which blocks come back. Defaults to ["roof", "property", "imagery", "storms", "solar"]. Pass a subset to skip work you don't need. Two storm-specific tokens: storms returns the storms block (just the last event by default), and storm_history expands it to the full 2-year event list — see Storm-only data. A request with no premium layer (no roof / property / solar / imagery) — e.g. ["storms"] — is free on any key (no measurement runs, never billed). Add any premium layer and the call bills the per-record rate.
POST https://www.rooftap.app/api/v1/enrich
X-API-Key: rt_live_abc123...
Content-Type: application/json

{
  "address": "5701 W Loma Ln, Glendale, AZ 85302",
  "lead_id": "lead-9821",
  "owner_match_name": "Sarah Johnson"
}

Response shape

Free keys return storms, risk (FEMA), neighborhood (Census), and reactivation (when lead_date is sent). Paid keys add roof, property, solar, and data_quality. Numeric fields can be null when source data is missing, never 0 as a fallback. The field tables below marked paid are omitted on the free tier.

200 OK

{
  "ok": true,
  "lead_id": "lead-9821",
  "billable": true,
  "address": {
    "input":      "5701 W Loma Ln, Glendale, AZ 85302",
    "formatted":  "5701 W Loma Ln, Glendale, AZ 85302, USA",
    "lat":        33.5601,
    "lng":       -112.1888,
    "place_id":   "ChIJ..."
  },
  "roof": {
    "area_sqft":          4003,
    "squares":            44,
    "predominant_pitch":  "4/12",
    "complexity":         "cut_up",
    "num_facets":         9,
    "linear_measurements": {
      "drip_edge_ft": 457
    }
  },
  "gutter": {
    "linear_feet":             127,
    "downspout_count_estimate": 4
  },
  "siding": {
    "wall_sqft_estimate": 2540,
    "perimeter_ft":        254,
    "stories":               1
  },
  "solar": {
    "suitability":             "high",
    "max_panel_count":          34,
    "kw_potential":             13.6,
    "annual_kwh_potential":     14820,
    "max_array_area_sqft":      612,
    "sunshine_hours_per_year":  1820,
    "panel_capacity_watts":     400
  },
  "property": {
    "year_built":                 1972,
    "estimated_roof_age_years":   18,
    "owner_match":                true,
    "owner_occupied":             true,
    "lot_size_sqft":              7800,
    "stories":                    1,
    "bedrooms":                   3,
    "bathrooms":                  2,
    "last_sale_date":             "2024-09-12",
    "last_sale_price":            412000,
    "sold_within_12mo":           true
  },
  "storms": {
    "last_storm": {
      "date":           "2025-09-18",
      "type":           "hail",
      "hail_in":        1.75,
      "wind_mph":        null,
      "distance_miles":  2.5
    },
    "claim_eligible_window": {
      "event_date":     "2025-09-18",
      "expires":        "2027-09-18",
      "days_remaining": 463
    }
  },
  "verify_url": "https://www.rooftap.app/r/a1b2c3d4e5f6a7b8",
  "data_quality": {
    "confidence":      "high",
    "imagery_quality": "HIGH",
    "footprint_match": true
  }
}

Roof fields

FieldTypeDescription
roof.area_sqftnumberTotal roof area, square feet, computed from Solar API rooftop polygon.
roof.squaresnumberRoofing squares (area_sqft / 100). Headline number for roofers.
roof.predominant_pitchstringMost-common pitch across roof facets, format "X/12".
roof.complexityenumOne of `simple` | `moderate` | `cut_up`. Drives waste % + labor estimates.
roof.num_facetsnumberDistinct roof planes detected. Higher = more complex.
roof.linear_measurements.drip_edge_ftnumberBuilding outline perimeter, eaves + rakes summed. Drives drip-edge material quantity. Auto-mode reports ship this field only; per-edge breakdowns (eaves/rakes/ridges/hips/valleys) are surfaced when the contractor manually labels edges on the verify page (HIGH-confidence override).

Gutter fields

FieldTypeDescription
gutter.linear_feetnumberTotal linear feet of gutter scope. Equals the roof's eave length (which is what gutters attach to).
gutter.downspout_count_estimatenumberRule-of-thumb 1 downspout per 35 ft of gutter, with a floor of 2. Adjust against the actual property if you have it.

Siding fields

FieldTypeDescription
siding.wall_sqft_estimatenumberWall surface area in square feet. Building perimeter × (stories × ~10 ft per story). Coarse but in the right ballpark for quoting.
siding.perimeter_ftnumberBuilding perimeter (the drip-edge length of the roof). Use directly for fascia + trim measurements.
siding.storiesnumberAbove-ground story count from property records. Defaults to 1 when records are missing.

Solar fields

FieldTypeDescription
solar.suitabilityenum`high` | `medium` | `low` | `unsuitable`. Single field for lead-aggregator routing. High = $80-150 solar lead; low/unsuitable = roof-only.
solar.max_panel_countnumberMaximum panels that fit on the roof per Google Solar API. Buyers use this for system sizing.
solar.kw_potentialnumberMax system DC capacity in kilowatts. Derived from max_panel_count × panel_capacity_watts.
solar.annual_kwh_potentialnumberEstimated annual generation in kWh at maximum system size. Drives payback + savings calcs.
solar.max_array_area_sqftnumberUsable rooftop area for panels in square feet.
solar.sunshine_hours_per_yearnumberAnnual sun-hours at this latitude/orientation. Lower = lower suitability.
solar.panel_capacity_wattsnumberAssumed per-panel rating used in the math (Google Solar API default, typically 250-400W).

Property fields

FieldTypeDescription
property.year_builtnumberYear the structure was built, per county assessor records.
property.estimated_roof_age_yearsnumberBest-effort roof age. Derived from permit history when available; falls back to year_built.
property.owner_matchbooleantrue when `owner_match_name` from the request matches the deed-of-record. Filters wholesalers + storm-chasers.
property.owner_occupiedbooleantrue when the property's mailing address matches the property address (homestead heuristic).
property.lot_size_sqftnumberParcel size in square feet, from county records.
property.storiesnumberNumber of above-ground stories. Drives labor + safety equipment cost.
property.bedroomsnumberBedroom count, county-assessor data.
property.bathroomsnumberBathroom count, county-assessor data.

Storm fields

FieldTypeDescription
storms.last_stormobject | nullThe single most recent NOAA storm event within 10 miles, returned by default on every call: { date (YYYY-MM-DD), type (`hail` | `wind` | `tornado` | `hurricane` | `tropical storm`), hail_in, wind_mph, distance_miles }. `null` when there's no qualifying event in the 2-year window.
storms.claim_eligible_windowobject | nullDerived window when a homeowner can still file an insurance claim for damage from the last event: { event_date, expires (event_date + 24mo), days_remaining }. `null` when there's no qualifying event. Storm-chaser roofers use this to time outreach.
storms.eventsarrayFull event list, newest first (max 50). Returned ONLY when you pass include=["storm_history"]. Each: { noaa_event_id, event_type, event_date, hail_size_inches, wind_speed_mph, city, state_abbr, distance_miles, damage_description }.
storms.max_hail_inchesnumber | nullLargest hail diameter across the 2-year window, in inches. Included with `storm_history`. `null` if no hail on record.
storms.max_wind_mphnumber | nullHighest wind gust across the 2-year window, in mph. Included with `storm_history`. `null` if none on record.
storms.lookback_yearsnumberYears of NOAA history searched. Currently 2. Included with `storm_history`.
storms.radius_milesnumberSearch radius around the subject property, in miles. Currently 10. Included with `storm_history`.

Contact compliance fields (premium add-on)

FieldTypeDescription
contact_compliance.tcpa_safe_to_callboolean | nullResult of federal + state DNC scrub against the contact phone. Only relevant for outbound cold outreach. Inbound consumer-initiated forms are TCPA-exempt.
contact_compliance.dnc_listedboolean | nullTrue if the phone is on the federal Do-Not-Call list.
contact_compliance.last_checkedstringISO timestamp of the last scrub. Cached 24h to avoid repeat upstream charges.

Quality + meta

FieldTypeDescription
verify_urlstring | nullShareable link to a hosted, presentable measurement report for this exact lookup — roof wireframe, measurements, solar, storm history and property details, with a one-click PDF download. Returned on every billable (paid) call; attach it to a CRM deal or job, or hand it to the homeowner. Link lives at `https://www.rooftap.app/r/<token>` and stays live ~30 days. `null` only on the rare best-effort issuance failure. See Measurement report below.
data_quality.imagery_qualityenum`HIGH` | `MEDIUM` | `LOW`. LOW indicates canopy occlusion or stale imagery.
data_quality.footprint_matchbooleantrue when our roof polygon aligns with the parcel's primary structure footprint.
billablebooleantrue when this call counts toward your monthly usage. false on quality-rejects, 4xx errors, and storm-only / free-layer calls (any request with no premium layer is free on any key).

Measurement report

Every billable call returns a verify_url — a shareable link to a hosted, presentable measurement report for that exact lookup. No need to render the JSON yourself: the page shows the roof wireframe, area / facets / pitch, edge measurements, solar potential, storm history and property details, with a one-click PDF download. It's the same report viewer homeowners see, served at https://www.rooftap.app/r/<token>.

"verify_url": "https://www.rooftap.app/r/a1b2c3d4e5f6a7b8"

Drop it straight onto a CRM deal or job (e.g. a JobTread job or a HubSpot deal property), or hand it to the homeowner. The link stays live for about 30 days — long enough to survive a typical lead-to-close cycle. On a medium/low-confidence read (data_quality.refinement_recommended: true) the page also lets the contractor refine the building selection; high-confidence reads get the link too, with nothing to refine. The field is nullonly on the rare best-effort issuance failure — re-call to get a fresh one. Storm-only / free-layer calls don't run a measurement, so they don't carry a verify_url.

POST /v1/enrich/prewarm

Optional. Hit this at lead intake to kick off the enrichment fetch in the background. Returns 202 in under 50ms, the next/v1/enrich call on the same address (the one that runs when your routing decision happens) lands a warm cache and returns sub-500ms.

Prewarm calls don't bill. Only the real call does.

POST https://www.rooftap.app/api/v1/enrich/prewarm
X-API-Key: rt_live_abc123...

{ "address": "5701 W Loma Ln, Glendale, AZ 85302",
  "lead_id":  "lead-9821" }

202 Accepted · <50ms
{ "ok": true, "lead_id": "lead-9821",
  "message": "Prewarm queued. Hit POST /v1/enrich on the same address in 2-6s for a cache hit." }

Bulk reactivation

Run an aged lead list back through NOAA storm history to find the homeowners worth a call today. This is storm-only screening(NOAA storm history + a worth-a-call-today flag + optional ongoing next-storm monitoring), not a full enrich. It's async + batched: you enqueue a job and poll for results (or wait for a webhook). Use it to wake a dormant CRM, not to measure a roof, when you need measurements use /v1/enrich.

Single-address checks are always free — call /v1/enrich one address at a time, unlimited. The price here is only for bulk batch processing: the first 1,000 addresses are free, then $0.01 per address, so a 50,000-address bulk run is $500, far below the $3.95 full-enrich rate, because reactivation only screens storm history.

POST /v1/reactivate

Enqueue an async batch of up to 1,000 addresses per request. Authenticate with the same X-API-Key header you use for /v1/enrich. Returns 202 immediately with a job_id and a status_url to poll. For a 50k+ list, split into chunks of 1,000 and POST each chunk, every chunk returns its own job_id.

FieldTypeDescription
addressesarray · requiredUp to 1,000 entries. Each entry is either a free-form address string, or an object { address, external_ref? } where external_ref is echoed back so you can correlate to your CRM.
monitorbooleanDefault true. When true, every address is enrolled in ongoing next-storm monitoring so you're alerted the next time a qualifying event lands.
emailstringOptional. We email this address a summary when the job finishes.
webhook_urlstringOptional. https only. We POST a completion event here when the job finishes (see below).
curl -X POST https://www.rooftap.app/api/v1/reactivate \
  -H "X-API-Key: rt_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "addresses": [
      "5701 W Loma Ln, Glendale, AZ 85302",
      { "address": "1804 E Vista Ave, Phoenix, AZ 85020", "external_ref": "lead-9821" }
    ],
    "monitor": true,
    "email": "ops@yourcompany.com",
    "webhook_url": "https://yourcompany.com/hooks/rooftap"
  }'

202 Accepted
{
  "ok": true,
  "job_id": "rjb_7f3c9a2e",
  "queued": 2,
  "status": "queued",
  "status_url": "https://www.rooftap.app/api/v1/reactivate/rjb_7f3c9a2e",
  "message": "Batch queued. Poll status_url or wait for the completion webhook."
}

The 202 body carries ok, job_id, queued (count accepted this request), status ("queued"), status_url, and a message.

Errors specific to this endpoint:

HTTPCodeWhat to do
401invalid_keyHeader missing or key unrecognized. Same key as /v1/enrich.
402upgrade_requiredFree keys get 1,000 addresses free for the lifetime of the key. Past that you must upgrade to continue at $0.01/address.
400chunk_too_largeMore than 1,000 addresses in one request. Split into chunks of 1,000 and POST each.
429rate_limitedMax 60 batches per minute per key. Honor Retry-After.

GET /v1/reactivate/{job_id}

Poll job status and pull results. Authenticate with X-API-Key, you can only read your own jobs. status moves queuedprocessing completed (or failed).

Query paramTypeDescription
includestringsummary returns just the summary block and omits results.
statusstringfollow_up filters results to hot leads only (the worth-a-call-today addresses).
limitnumberPage size. Max 1,000, default 500.
offsetnumberResult offset for paging.
curl https://www.rooftap.app/api/v1/reactivate/rjb_7f3c9a2e?status=follow_up \
  -H "X-API-Key: rt_live_abc123..."

200 OK
{
  "ok": true,
  "job_id": "rjb_7f3c9a2e",
  "status": "completed",
  "summary": {
    "total":       2,
    "processed":   2,
    "follow_ups":  1,
    "monitored":   2,
    "errors":      0
  },
  "results": [
    {
      "address":               "5701 W Loma Ln, Glendale, AZ 85302",
      "external_ref":           null,
      "status":                "done",
      "matched":                true,
      "last_event":            "2026-05-26",
      "max_hail_in":            1.75,
      "events_5yr":             4,
      "worth_following_up":     true,
      "trigger":               { "date": "2026-05-26", "type": "hail", "hail_in": 1.75, "wind_mph": null },
      "days_since_last_storm":  8,
      "claim_window_days":      365,
      "within_claim_window":    true,
      "priority":               1,
      "monitored":              true
    }
  ],
  "paging": { "limit": 500, "offset": 0, "returned": 1 }
}

The response carries ok, job_id, status, a summary block (total, processed, follow_ups, monitored, errors), the results array, and paging (limit, offset, returned).

Reactivation result fields

FieldTypeDescription
addressstringThe address as supplied in the request.
external_refstring | nullYour reference, echoed back when you passed the object form `{ address, external_ref }`. `null` for bare-string entries.
statusenum`done` once processed, or `error` if the address couldn't be checked. Use `worth_following_up` for the hot-lead flag, not this.
matchedbooleantrue when the address geocoded and matched a parcel with NOAA storm history.
last_eventstring | nullDate of the most recent qualifying storm event near this address. ISO format (YYYY-MM-DD), `null` if none.
max_hail_innumber | nullLargest hail diameter in inches across the screened history. `null` if no hail on record.
events_5yrnumberCount of qualifying storm events in the last 5 years within range of this address.
worth_following_upbooleanThe headline flag. true when a storm since the lead date makes this a worth-a-call-today reactivation candidate.
triggerobject | nullThe storm that flagged the address: `{ date, type, hail_in, wind_mph }`. `null` when `worth_following_up` is false.
days_since_last_stormnumber | nullWhole days since the most recent severe (qualifying) storm. `null` when there's no qualifying storm on record.
claim_window_daysnumberThe address state's property-claim window in days, used to rank this lead. Defaults to 730 (2 years) when the state can't be determined.
within_claim_windowbooleanWhether the most recent storm is still inside that claim window.
prioritynumber | nullCall-priority, 1 = call first through 5 = floor (lowest). `null` when there's no qualifying storm. Results are returned sorted by `priority` ascending (1 first).
monitoredbooleantrue when this address was enrolled in ongoing next-storm monitoring (driven by the request `monitor` flag).

priority is a call-ordering heuristic, not legal or insurance advice. We rank fresher storms higher so your team works the list top-down. The scale:

  • 1 - severe storm 14 days ago or less.
  • 2 - 15 to 90 days ago.
  • 3 - 91 to 365 days ago.
  • 4 - 366 days up to the state's claim window (only reachable in 2-year states).
  • 5 - past the state's claim window, or older than 2 years. Still listed, just the lowest rank.

The claim window is per US state (roughly 1 to 2 years) and is a best-effort heuristic. When we can't determine the state we default to 2 years (claim_window_days: 730). Leads are never dropped: anything past the window simply floors to priority 5.

Completion webhook

Optional. If you set webhook_urlon the enqueue call, we POST a completion event there when the job finishes, so you don't have to poll.

POST https://yourcompany.com/hooks/rooftap
Content-Type: application/json

{
  "event":   "reactivation.completed",
  "job_id":  "rjb_7f3c9a2e",
  "summary": {
    "total":      50000,
    "processed":  50000,
    "errors":     0,
    "follow_ups": 3142,
    "monitored":  50000
  }
}

Errors

All errors return JSON with { ok: false, error, message }. The error field is a stable machine-readable code; message is human-readable and may change between releases.

401 Unauthorized · invalid_key
{ "ok": false, "error": "invalid_key",
  "message": "X-API-Key header missing or unrecognized." }

422 Unprocessable Entity · address_unresolvable
{ "ok": false, "error": "address_unresolvable",
  "message": "Could not geocode the supplied address.",
  "billable": false }

429 Too Many Requests · rate_limited
{ "ok": false, "error": "rate_limited",
  "message": "Rate limit: 10 rps. Retry after 600ms." }
// Honor the Retry-After response header.
HTTPCodeWhat to do
400invalid_jsonBody wasn't valid JSON. Check Content-Type + payload.
400address_requiredMissing address field.
401invalid_keyHeader missing or key revoked. Rotate via support.
402billing_requiredSubscription payment failed. Update card in your billing portal.
422address_unresolvableGeocoder couldn't place the address. Not billed.
422no_solar_coverageAddress is outside Solar API coverage. Not billed.
429rate_limitedHonor Retry-After header. Default cap 10 rps per key.
500internal_errorOur fault. Retry with exponential backoff. Not billed.

Rate limits

  • /v1/enrich - 10 rps per API key. 429 returns a Retry-After header in seconds.
  • /v1/enrich/prewarm - 30 rps per API key (separate bucket).
  • Need higher caps for an aggregator burst? Email support, we lift to 50+ rps once we see your traffic profile.

Billing

Volume tiers are auto-applied for the entire month based on your final volume. Run 16,000 billable calls in a month and every one that period prices at $2.45, including the first 5,000. Only calls that request a premium layer are billable — storm-only / free-layer calls (billable: false) don't count toward your volume or your bill.

Each billable call is charged independently, including repeat lookups of the same address. Results are licensed for the end customer whose lookup triggered the call: don't store and re-serve our data to other third parties in place of a fresh call. One end-customer lookup, one call.

VolumePer callNotes
0 – 5,000 / mo$3.95Entry tier, no minimum.
5,001 – 15,000 / mo$3.25Auto-applied.
15,001 – 30,000 / mo$2.45Auto-applied.
30,000+ / mo$1.95Email support for >100k contracts.

Quality guarantee

We never bill for bad data.If we can't place the address, can't resolve a roof polygon with confidence, or the underlying imagery is canopy-occluded, the response includes billable: falseand that call doesn't count toward your usage. No tickets, no clawbacks, no end-of-month reconciliation.

Changelog

  • 2026-06 - Storm block reworked. Responses now return a single storms.last_storm event by default (plus claim_eligible_window); pass include: ["storm_history"] for the full event list. The history window is now 2 years (was 5), aligned to the claim window. Storm-only calls (any request with no premium layer, e.g. include: ["storms"]) are now free on every key — no measurement runs and they're never billed, even on a paid key. Breaking: the old storm.hail_2024 / hail_5yr_count / wind_5yr_max fields are replaced by the structured storms block.
  • 2026-06 - Bulk reactivation launched. Async batch storm-screening for aged lead lists: POST /v1/reactivate + GET /v1/reactivate/{job_id}, first 1,000 addresses free, then $0.01/address, with optional ongoing next-storm monitoring and a completion webhook.
  • 2026-05 - Storm Alerts webhook API launched in free beta. Register addresses, get signed POSTs when qualifying hail/wind events land within 10 mi. linear_measurements slimmed to drip_edge_ft only in auto-mode reports; per-edge fields ship when the report is refined via the on-screen labeling tool. Storm 5-year wind max added.
  • 2026-04 - Prewarm endpoint launched. Volume tier breakpoints widened.
  • 2026-03 - owner_match_name request parameter live.
  • 2026-02 - v1 GA. Public launch.
Ship today

60-second self-serve key. Card on file via Stripe.

No NDA. No procurement loop. Cancel any time.

Get an API key →