Skip to content

Latest commit

 

History

History
773 lines (559 loc) · 188 KB

README.md

File metadata and controls

773 lines (559 loc) · 188 KB

Permits

Overview

Search and retrieve building permits

Available Operations

search_permits

Search building permits by location, date, category, contractor and more.

Filters combine with AND. Supply at least one narrowing filter -- a city, ZIP, jurisdiction, date range or lat/lng radius -- for a query that returns quickly.

Results are paginated and ordered newest-first on the permit's best available date (date_issued, falling back to date_filed). total is exact up to 10,000; beyond that it stops counting and returns total: 10000 with total_capped: true, meaning "10,000 or more". If the count cannot finish in time the response carries total: null with total_unknown: true -- an unknown total is reported as unknown and never as a number. Rows are unaffected either way; page through them normally.

category=hvac matches HVAC and MECHANICAL together, because AC and furnace work is filed under either depending on the city. Unknown parameter names are rejected with a 400 rather than ignored, so a typo can never silently return unfiltered results.

Free-tier keys are limited to a recent window; paid tiers have full history.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.search_permits(radius_miles=5.0, fields="summary", record_kind="permit", page=1, per_page=25, count_only=False)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
zip_code OptionalNullable[str] ➖ 5-digit ZIP code
city OptionalNullable[str] ➖ City name
state OptionalNullable[str] ➖ 2-letter state code
jurisdiction OptionalNullable[str] ➖ Jurisdiction name (e.g. 'Wake County', 'Tacoma') or partial match
address OptionalNullable[str] ➖ Street address, partial + case-insensitive (e.g. '1600 Pennsylvania') — indexed, fast
lat OptionalNullable[float] ➖ Latitude for radius search
lng OptionalNullable[float] ➖ Longitude for radius search
radius_miles Optional[float] ➖ Radius in miles (used with lat/lng)
fields Optional[str] ➖ 'summary' (default) or 'full'. With 'full' each result is a PermitDetail rather than a PermitSummary -- the same nine extra columns GET /v1/permits/{id} returns (record_kind, date_expired, fee_amount, stories, units, square_footage, applicant_name, contractor_license, created_at) -- so you do not fetch them one permit at a time. See the PermitDetail schema for their types; the declared response schema here is PermitSummary, which is the default shape. Developer plan and above.
bbox OptionalNullable[str] ➖ Map-viewport bounding box 'minLng,minLat,maxLng,maxLat'. Returns permits whose location falls inside the box (geocoded permits only).
polygon OptionalNullable[str] ➖ A drawn area as a GeoJSON Polygon geometry (URL-encoded), e.g. {"type":"Polygon","coordinates":[[[lng,lat],...]]}. Returns permits inside the polygon (geocoded permits only).
category OptionalNullable[str] ➖ Permit category (e.g. solar, SOLAR, roofing, hvac — case insensitive)
status OptionalNullable[models.PermitStatus] ➖ Permit status (e.g. issued, filed, final)
property_type OptionalNullable[models.PropertyType] ➖ Property type (e.g. residential, commercial)
tag OptionalNullable[str] ➖ Filter by tag
record_kind Optional[str] ➖ Record kind: 'permit' (default, building permits only), 'contractor', 'tag', 'non_building', 'admin', or 'all'
filed_after datetime ➖ Filed on or after this date
filed_before datetime ➖ Filed on or before this date
issued_after datetime ➖ Issued on or after this date
issued_before datetime ➖ Issued on or before this date
date_after datetime ➖ On or after this date, matched against whichever date a record has (issued, else filed). Use this when a source populates only one of issued/filed — e.g. issued-only feeds vs filed-only feeds.
date_before datetime ➖ On or before this date, matched against whichever date a record has (issued, else filed).
parcel OptionalNullable[str] ➖ Parcel number / APN / folio (formatting ignored). Returns permits on that parcel where the source publishes one.
min_value OptionalNullable[float] ➖ Minimum estimated value
max_value OptionalNullable[float] ➖ Maximum estimated value
min_solar_kw OptionalNullable[float] ➖ Minimum extracted solar system size (kW DC)
max_solar_kw OptionalNullable[float] ➖ Maximum extracted solar system size (kW DC)
min_sqft OptionalNullable[float] ➖ Minimum square footage mentioned (from enrichment)
has_enrichment OptionalNullable[bool] ➖ Only permits that have (true) or lack (false) LLM enrichment
scope OptionalNullable[str] ➖ Substring match on the enriched work scope
q OptionalNullable[str] ➖ Case-insensitive substring match across description, address, and permit number. Terms under 3 characters are matched but not counted: total is null with total_unknown=true (a 1-2 character term has no trigram index and the count would cost tens of seconds).
contractor_name OptionalNullable[str] ➖ Contractor name (partial match)
owner_filed OptionalNullable[bool] ➖ true = owner-filed permits only (no contractor on record but an owner name is present — often a DIY/homeowner lead, though for feeds that don't capture contractors the owner may be a builder or institution); false = permits that have a contractor
has_owner_address OptionalNullable[bool] ➖ true = only permits that carry a property-owner mailing address; false = only those that do not. Coverage varies sharply by jurisdiction (we hold the county assessor roll for some and not others), so this is a targeting filter rather than a defect: it returns exactly the rows that are actionable. The address itself is visible on Business and above.
page Optional[int] ➖ N/A
per_page Optional[int] ➖ Results per page. Above your plan's maximum this is clamped, not rejected; the response echoes the per_page actually applied.
keyword OptionalNullable[str] ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of q.
date_from datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_after.
date_to datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_before.
start_date datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_after.
end_date datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_before.
limit OptionalNullable[int] ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of per_page. Clamped to your plan's maximum, not rejected.
count_only Optional[bool] ➖ Return only the total for these filters -- no permit records. Skips the row fetch entirely, so it is markedly cheaper for both of us when you are sizing a query rather than reading it. results comes back empty and total_capped / total_unknown mean exactly what they always do.
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitSearchResponse

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

export_permits

Export permits matching filters as CSV. Tier-gated row limits.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.export_permits(record_kind="permit", limit=1000)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
zip_code OptionalNullable[str] ➖ N/A
city OptionalNullable[str] ➖ N/A
state OptionalNullable[str] ➖ N/A
category OptionalNullable[str] ➖ N/A
status OptionalNullable[models.PermitStatus] ➖ N/A
property_type OptionalNullable[models.PropertyType] ➖ N/A
tag OptionalNullable[str] ➖ N/A
record_kind Optional[str] ➖ N/A
filed_after datetime ➖ N/A
filed_before datetime ➖ N/A
issued_after datetime ➖ N/A
issued_before datetime ➖ N/A
date_after datetime ➖ On or after this date, matched against whichever date a record has (issued, else filed).
date_before datetime ➖ On or before this date, matched against whichever date a record has (issued, else filed).
parcel OptionalNullable[str] ➖ Parcel number / APN / folio (formatting ignored).
min_value OptionalNullable[float] ➖ N/A
max_value OptionalNullable[float] ➖ N/A
min_solar_kw OptionalNullable[float] ➖ N/A
max_solar_kw OptionalNullable[float] ➖ N/A
min_sqft OptionalNullable[float] ➖ N/A
has_enrichment OptionalNullable[bool] ➖ N/A
scope OptionalNullable[str] ➖ N/A
q OptionalNullable[str] ➖ N/A
contractor_name OptionalNullable[str] ➖ N/A
owner_filed OptionalNullable[bool] ➖ true = owner-filed permits only (no contractor on record, owner name present — often DIY/homeowner leads, though for feeds without contractor capture the owner may be a builder/institution); false = permits that have a contractor
jurisdiction OptionalNullable[str] ➖ A jurisdiction's id (from /v1/jurisdictions) or its name, partial and case-insensitive -- the same matching as /v1/permits/search. Lets a full load be partitioned along the coverage list.
limit Optional[int] ➖ Rows to return, up to your plan's export maximum (a larger value is refused with 403, never silently lowered). If more rows match than limit, the response header X-Permitstack-Truncated is true: narrow the filter or split the date range and export again.
keyword OptionalNullable[str] ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of q.
date_from datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_after.
date_to datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_before.
start_date datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_after.
end_date datetime ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of date_before.
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

str

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

sync_permits

Incremental data feed (change-data-capture). Page the dataset ordered by (updated_at, id). Omit cursor for the initial full load; persist next_cursor and pass it back after each nightly ingest to receive only new + changed permits. Upsert-only (deletes are not emitted).

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.sync_permits(limit=5000, record_kind="permit", fields="summary")

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
cursor OptionalNullable[str] ➖ Opaque cursor from the previous response's next_cursor. Omit to start the initial full sync from the beginning.
since OptionalNullable[str] ➖ Alternative start point: an ISO-8601 UTC timestamp; returns permits with updated_at >= since. Ignored when cursor is supplied.
limit Optional[int] ➖ Max permits per page (cursor page size, up to 50,000).
record_kind Optional[str] ➖ 'permit' (default), a specific record_kind, or 'all'.
state OptionalNullable[str] ➖ Optional 2-letter state filter to scope the feed.
category OptionalNullable[str] ➖ Optional category filter (e.g. solar, roofing).
fields Optional[str] ➖ 'summary' (default) or 'full'. 'full' adds record_kind, date_expired, fee_amount, stories, units, square_footage, applicant_name, contractor_license and created_at to every record, so a mirror does not have to fetch them one permit at a time. OPT-IN: the default payload is unchanged apart from contractor_id, added on 2026-09-10 to every permit surface; widening a feed under a consumer with a strict schema is otherwise avoided.
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

Any

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

list_permit_events

What CHANGED, instead of re-reading everything: permit transitions (new_permit, status_change, issued, completed, expired) built from the daily ingest diff, filterable by city, state, category and jurisdiction.

This is the endpoint to poll on a schedule, and cursor is how to poll it. Save the next_cursor from each response and pass it back as cursor on the next call; you then receive only what you have not already seen, in the order it was detected, with no duplicates and no gap. Page until a response comes back shorter than per_page, save that last next_cursor, and resume there tomorrow.

WHERE YOU START MATTERS, AND THE FIRST CALL DOES NOT START AT THE BEGINNING. A call with NO cursor returns the NEWEST events and its next_cursor is the frontier -- a watermark at "now". Pass it straight back and you correctly get 0 results, because you have just declared yourself caught up. That is exactly what a poller wants: from here on you receive everything new. It is NOT a backfill, and it will not walk history for you -- there are 75,544 events behind that watermark for the Tampa filter below alone.

To start somewhere else, build the cursor yourself: it is <ISO-8601 timestamp>|<event id>, and |0 is a valid id floor.

# start polling from now (typical):
GET /v1/permits/events?city=Tampa&state=FL&category=roofing
    &event_type=new_permit                       -> save next_cursor
# ...then, from the next call onward:
GET ...&cursor=2026-09-08T04%3A09%3A16.381111%2B00%3A00%7C51823904

# start from a chosen point instead (backfill the last 30 days, then keep polling):
GET ...&cursor=2026-08-11T00%3A00%3A00%2B00%3A00%7C0

One call answers what a paged re-pull of /v1/permits/search costs hundreds of. Measured 2026-09-09, that Tampa query returns 38 records in a single call; the same question asked by re-pulling search pages 1-100 twelve times a day costs ~9,600 requests and runs into the daily cap.

detected_after still works and is fine for an ad-hoc look at a window, but it is the wrong tool for a poller: it is INCLUSIVE, and one ingest batch stamps thousands of events with a single identical detected_at (measured 2026-09-10: 3,688 timestamps carry over 1,000 events each, the largest 1,370,561). A poller that stores the newest detected_at and passes it back therefore re-receives that whole batch every time. cursor breaks the tie on the event id and does not.

Supplying a cursor returns events oldest-unseen first, which is what lets a batch be paged safely; without one you get the newest first, for browsing. cursor and page are alternatives -- passing both is a 400 rather than a silently skipped page.

Ingest runs once a day, so a daily poll is enough; detected_at is when WE saw the change, not when the city recorded it. For push instead of poll, register a webhook (developer tier and above) and skip the polling entirely.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.list_permit_events(page=1, per_page=50)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
event_type OptionalNullable[str] ➖ Filter by event type: new_permit, status_change, issued, completed, expired (the permit's expiration date has passed without it being finished; emitted when that date arrives)
category OptionalNullable[str] ➖ Permit category (e.g. solar, battery)
city OptionalNullable[str] ➖ City name
state OptionalNullable[str] ➖ 2-letter state code
jurisdiction OptionalNullable[str] ➖ Jurisdiction name (partial)
permit_id OptionalNullable[str] ➖ Events for a single permit id
detected_after date ➖ Only events detected on/after this UTC timestamp (ISO 8601). Inclusive, so a batch sharing one timestamp is re-delivered; prefer cursor for polling.
cursor OptionalNullable[str] ➖ Opaque cursor from the previous response's next_cursor. Resumes exactly where you stopped, with no duplicates and no gap. Omit on the first call.
page Optional[int] ➖ N/A
per_page Optional[int] ➖ N/A
limit OptionalNullable[int] ➖ : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.

Alias of per_page. Clamped to 100, not rejected.
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitEventsResponse

Errors

Error Type Status Code Content Type
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

get_permit

Get full details for a single permit.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.get_permit(permit_id="8b0513b0-82c1-4220-9ede-cf81253853d0")

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
permit_id str ✔️ N/A
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitDetail

Errors

Error Type Status Code Content Type
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

get_permits_by_address

Get all permits for a specific address (partial match).

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.get_permits_by_address(address="5701 Alexanne Point", page=1, per_page=25, record_kind="permit")

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
address str ✔️ N/A
page Optional[int] ➖ N/A
per_page Optional[int] ➖ N/A
record_kind Optional[str] ➖ 'permit' (default), a specific record_kind, or 'all'.
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitSearchResponse

Errors

Error Type Status Code Content Type
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

get_coverage_stats

Coverage statistics: total permits, every jurisdiction we hold, and the counties they fall in.

Each jurisdiction carries data_through (the newest permit we actually hold, measured), plus county / county_fips (the county most of its permits fall in) and counties (the full measured mix with a share of the sample per county, since some cities straddle a county line). counties at the top level is the same data keyed by county, listing the jurisdictions whose permits fall in each one. A null county means not measured, which is the case for statewide feeds that publish no coordinates.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.get_coverage_stats()

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

Any

Errors

Error Type Status Code Content Type
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

list_plays

List available trade plays and their parameters.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.list_plays()

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

Any

Errors

Error Type Status Code Content Type
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

system_age

Addresses whose LATEST permit in the trade is min–max years old with nothing since — the system is statistically due for replacement. Only trades with a real lifecycle are supported (roofing, hvac, mechanical, solar=repower, pool).

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.system_age(trade="<value>", page=1, per_page=25)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
trade str ✔️ roofing | hvac | mechanical | solar | pool
state OptionalNullable[str] ➖ 2-letter state code
city OptionalNullable[str] ➖ City name
zip_code OptionalNullable[str] ➖ 5-digit ZIP
jurisdiction OptionalNullable[str] ➖ Jurisdiction name (partial)
min_age_years OptionalNullable[float] ➖ Override the trade's default minimum age
max_age_years OptionalNullable[float] ➖ Override the trade's default maximum age
page Optional[int] ➖ N/A
per_page Optional[int] ➖ N/A
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitSearchResponse

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

battery_retrofit_candidates

Solar permits aged between min/max years whose address has NO battery permit on file — the storage-retrofit lead list. Requires a location filter.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.battery_retrofit_candidates(min_age_years=2.0, max_age_years=7.0, page=1, per_page=25)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
state OptionalNullable[str] ➖ 2-letter state code
city OptionalNullable[str] ➖ City name
zip_code OptionalNullable[str] ➖ 5-digit ZIP
jurisdiction OptionalNullable[str] ➖ Jurisdiction name (partial)
min_age_years Optional[float] ➖ Minimum age of the PV permit, in years
max_age_years Optional[float] ➖ Maximum age of the PV permit, in years
page Optional[int] ➖ N/A
per_page Optional[int] ➖ N/A
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitSearchResponse

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

reroof_due

Roofing permits aged min-max years whose address has NO newer roofing permit — homes whose roof is statistically due for replacement. Alias of /v1/plays/system-age?trade=roofing (kept as the discoverable roofing-first name).

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.reroof_due(min_age_years=12.0, max_age_years=25.0, page=1, per_page=25)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
state OptionalNullable[str] ➖ 2-letter state code
city OptionalNullable[str] ➖ City name
zip_code OptionalNullable[str] ➖ 5-digit ZIP
jurisdiction OptionalNullable[str] ➖ Jurisdiction name (partial)
min_age_years Optional[float] ➖ Minimum age of the roofing permit, in years
max_age_years Optional[float] ➖ Maximum age of the roofing permit, in years
page Optional[int] ➖ N/A
per_page Optional[int] ➖ N/A
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitSearchResponse

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

orphan_recovery

PV permits whose installer (contractor, applicant, or owner) matches installer in a territory — a named competitor's customer base. Requires a location filter.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.orphan_recovery(installer="<value>", page=1, per_page=25)

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
installer str ✔️ Installer name to match (contractor/applicant/owner)
state OptionalNullable[str] ➖ 2-letter state code
city OptionalNullable[str] ➖ City name
zip_code OptionalNullable[str] ➖ 5-digit ZIP
jurisdiction OptionalNullable[str] ➖ Jurisdiction name (partial)
page Optional[int] ➖ N/A
per_page Optional[int] ➖ N/A
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

models.PermitSearchResponse

Errors

Error Type Status Code Content Type
errors.FeatureLockedError 403 application/json
errors.HTTPValidationError 422 application/json
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*

list_covered_jurisdictions

Every jurisdiction we cover, with how current and how complete each one is.

data_through is the newest permit we actually hold, measured -- not when we last polled the source. freshness_label and completeness_label are the same sentences the export picker and the delivered manifest use, so this can never disagree with them.

Example Usage

import os
from permitstack import Permitstack


with Permitstack(
    api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:

    res = p_client.permits.list_covered_jurisdictions()

    # Handle response
    print(res)

Parameters

Parameter Type Required Description
retries Optional[utils.RetryConfig] ➖ Configuration to override the default retry behavior of the client.

Response

Any

Errors

Error Type Status Code Content Type
errors.ErrorDetail 401, 429 application/json
errors.PermitstackDefaultError 4XX, 5XX */*