Pull the permit history of any address at quote time: the last permitted roof, HVAC, solar and pool work, additions and demolitions. When nothing matches, the API tells you whether that means no permit or no coverage.
No credit card required. 100 free requests/day.
# Roof, HVAC and renovation dates for one address
curl "https://api.permit-stack.com/v1/property/history?address=10517%2035th%20Ave%20NE\
&city=Seattle\
&state=WA" \
-H "X-API-Key: pk_your_key_here"
# "last_roofing_date": "2026-09-16"
# "last_hvac_date": "2020-08-25"
# Seattle data through 2026-09-25 (current)Building permits are dated public records of work on a property. PermitStack normalizes 117M+ permits from 887 active data sources in 8,000+ cities across 48 states and DC, including 6.7M+ roofing permits, into one API. /v1/property/history turns an address into a permit timeline and a signals block with the latest roof, HVAC, solar and pool dates.
Every answer says how current its source is, and an empty answer says whether we cover that city. Start free, and check your market before you pay.
Reroofs, tear-offs and repairs, one of 20 categories in a 117M+ permit database.
The main ingest runs every day at 03:00 UTC, and each source reports the newest permit we actually hold.
100 free requests per day, no card. Free keys see the last 30 days of permits; paid plans remove the date limit.
Each example is a real request and a trimmed copy of the response it returned. The residential example has its street address redacted.
One call to /v1/property/history returns every permit we hold at the address and a signals block built from them: the most recent roofing, HVAC, solar and pool permit dates, plus flags for additions, new construction, demolition, electrical and plumbing work. That is a dated, attributable fact for rating a roof or a system without sending anyone out.
data_currency names each source behind the answer and how current it is, so the date you rate on comes with its own provenance.
# A public community center in Seattle
curl "https://api.permit-stack.com/v1/property/history?address=10517%2035th%20Ave%20NE\
&city=Seattle\
&state=WA" \
-H "X-API-Key: pk_your_key_here"{
"found": true,
"total_matches": 16,
"summary": {
"first_permit_date": "2007-11-14",
"last_permit_date": "2026-09-16",
"years_of_history": 19,
"categories": {"ELECTRICAL": 9, "ROOFING": 1, "HVAC": 1,
"MECHANICAL": 1, "DEMOLITION": 1, ...},
"signals": {
"has_roofing": true, "last_roofing_date": "2026-09-16",
"has_hvac": true, "last_hvac_date": "2020-08-25",
"has_solar": false, "has_pool": false,
"has_addition": false, "has_demolition": true,
...
}
},
"data_currency": [
{"jurisdiction": "Seattle", "data_through": "2026-09-25", "status": "current", ...},
{"jurisdiction": "Seattle Electrical", "data_through": "2026-09-26", "status": "current", ...},
{"jurisdiction": "Seattle Trade", "data_through": "2026-09-25", "status": "current", ...}
],
...
}A clean history is only useful if you know the city is covered. When nothing matches, the answer carries a coverage block. In a jurisdiction we hold and keep current it says so, with the data-through date and the number of permits on file. Where we do not cover the city it says to treat the result as unknown. Route the second case to your usual inspection or third-party process.
# An address with no permits in Boulder, CO
curl "https://api.permit-stack.com/v1/property/history?address=9999%20Arapahoe%20Ave\
&city=Boulder\
&state=CO" \
-H "X-API-Key: pk_your_key_here"{
"found": false,
"total_matches": 0,
"coverage": {
"confidence": "high",
"covered": true,
"jurisdiction": "Boulder",
"data_through": "2026-09-27",
"freshness": "current",
"note": "Boulder is an actively-updated covered jurisdiction
(338,034 permits on file, data through 2026-09-27). A 'no record'
result here most likely means no permit exists for this address
...", ...
}, ...
}# An address in a Texas city we do not cover
curl "https://api.permit-stack.com/v1/property/history?address=1000%20S%20Polk%20St\
&city=Amarillo\
&state=TX" \
-H "X-API-Key: pk_your_key_here"{
"found": false,
"total_matches": 0,
"coverage": {
"confidence": "none",
"covered": false,
"note": "This address's city does not match one of our covered
jurisdictions (we cover 47 active jurisdiction(s) in TX). Treat
'no record' as UNKNOWN unless the city itself is covered.", ...
}, ...
}After hail or wind, count roofing permits filed or issued in the affected city or ZIP to size restoration activity, then page through the addresses to match against your book. count_only=true skips the rows and returns just the total. Totals are exact up to 10,000; above that the API says total_capped rather than inventing a number.
# Roofing permits in Fort Worth since July 1
curl "https://api.permit-stack.com/v1/permits/search?city=Fort%20Worth\
&state=TX\
&category=roofing\
&date_after=2026-07-01\
&count_only=true" \
-H "X-API-Key: pk_your_key_here"{
"total": 217,
"results": [],
"total_capped": false,
"total_unknown": false, ...
}/v1/permits/sync is a cursor-based change feed: load a state or category once, then after each nightly ingest pull only the permits that are new or changed and join them to your policies on your side. Pages hold up to 50,000 permits. Developer plans can instead register webhooks (up to 10 per key) filtered by city, state, ZIP, category or keyword, dispatched within about 60 seconds of a permit reaching us.
# Texas roofing permits new or changed since Sept 28
curl "https://api.permit-stack.com/v1/permits/sync?state=TX\
&category=roofing\
&since=2026-09-28T00:00:00Z" \
-H "X-API-Key: pk_your_key_here"{
"results": [
{"permit_number": "RES-ROOF-26-001583", "status": "FILED",
"category": "ROOFING", "property_type": "RESIDENTIAL",
"address_street": "[redacted]", "address_city": "Dallas",
"address_state": "TX", "address_zip": "75208",
"description_raw": "RE-ROOF ON PROPERTY, REMOVE EXISTING ROOF, ...",
"date_filed": "2026-09-12", "estimated_value": null,
"updated_at": "2026-09-28T01:52:01Z", ...}
],
"count": 1,
"has_more": true,
"next_cursor": "2026-09-28T01:52:01.633660+00:00|28b9589d-..."
}Check that the roofer or restoration company on a claim has a permit track record: /v1/contractors/search returns permit counts, first and last permit dates, specialties and the licence number where the source publishes one. /v1/contractors/{id}/permits lists the jobs themselves.
# A Seattle commercial roofer
curl "https://api.permit-stack.com/v1/contractors/search?name=Axiom%20Division%207\
&state=WA" \
-H "X-API-Key: pk_your_key_here"{
"total": 4,
"results": [
{"name": "Axiom Division 7 Inc",
"license_number": "AXIOMD7920CF", "license_state": "WA",
"city": "SEATTLE", "state": "WA",
"total_permits": 43,
"first_permit_date": "2017-07-10",
"last_permit_date": "2026-09-10",
"specialties": ["roofing"], "score": 74, ...},
...
]
}A dated roof permit is strong evidence. An empty history is weak evidence unless the source is covered and current, so the API says which case you are in.
first_permit_date shows how far back an address's record reaches.FINAL, EXPIRED or CANCELLED. Where it does not, status is UNKNOWN. We do not have inspection records.data_through is the newest permit we hold, never the time we last polled. Sources are labelled current (under 45 days), lagging (under a year) or stale. A source that is refusing our requests is labelled as blocked rather than quietly aging.category=hvac returns both HVAC and MECHANICAL.city and state with an address to avoid matching the same street number in another metro. A lookup needs a house number and a street name.The coverage check is free and needs no account. It answers with the permits we hold for a city over the last 12 months, the date each source's data runs through, and whether that source is current or lagging. The same box sits in the pricing section of the homepage.
curl "https://api.permit-stack.com/v1/coverage/check?city=Austin&state=TX"Quote-time lookups and book refreshes both fit on Business for most carriers and MGAs. Developer suits a pilot on a few markets; Scale is for national books.
/v1/metrics monthly series and city rankingsfields=full on search/v1/permits/sync change feed (cursor-based)Every plan is self-serve through Stripe and you can start on the free tier (100 requests/day, last 30 days of permits). For licensing or redistribution, email support@permit-stack.com.
You can get the date of the most recent roofing permit on record: /v1/property/history returns last_roofing_date alongside the full permit list for the address. That is the last permitted roof work, which is usually the replacement date. If the roof was replaced without a permit, or before the source's history begins, it will not appear, so check first_permit_date and the coverage block.
Every found: false answer carries a coverage block. In a covered, current jurisdiction it reads covered: true with confidence high and a data-through date. Where we do not cover the city it reads covered: false and tells you to treat the result as unknown.
The signals block reports the latest HVAC, solar and pool permit dates and flags battery storage, additions, new construction, demolition, electrical and plumbing work. Solar permits include system size in kW where the source states it.
Sources are polled daily, with the main ingest at 03:00 UTC, and webhooks are dispatched within about 60 seconds of a permit reaching us. Some cities publish weeks after the fact, which is why every jurisdiction reports its own data_through date.
Business ($149/mo) fits most carriers and MGAs: 100,000 requests a day for quote-time lookups, the /v1/permits/sync change feed for book refreshes, and 200,000-row CSV exports. Scale ($499/mo) raises that to 500,000 requests a day with same-business-day support. For licensing or redistribution, email support@permit-stack.com.
Check before you pay. GET https://api.permit-stack.com/v1/coverage/check?city=Austin&state=TX needs no key and returns the permits we hold for that city over the last 12 months and how current each source is. The same check is in the pricing section of the homepage.
117M+ permits · 6.7M+ roofing · 887 active data sources · data-through date on every answer