Sfplanninggis APIsfplanninggis.org ↗
Access SF parcel records, historic Assessor photos, preservation surveys, planning applications, and building permits via the sfplanninggis.org API.
What is the Sfplanninggis API?
This API exposes 3 endpoints covering San Francisco parcel identity, historic Assessor photographs (roughly 105,000 citywide records), historic preservation surveys, planning documents, and building permit records from the SF Planning Property Information Map. The search_properties endpoint resolves address prefixes, street names, or block/lot strings to Assessor block/lot identifiers, which can then be passed to get_property_evidence to retrieve the full evidence record set for a specific parcel.
curl -X GET 'https://api.parse.bot/scraper/0e1a9ee5-ace1-44ca-8b0a-fb3b009ad55f/search_properties?query=237+Cortland' \ -H 'X-API-Key: $PARSE_API_KEY'
Finds candidate parcels whose recorded address, street name or block/lot begins with the query (case-insensitive prefix match, e.g. '237 Cortland', 'Seal Rock' or '1481001'). Each candidate is one Assessor block/lot with every address recorded for it and the public property page URL; block and lot are also split out. Results are ordered by parcel and paged: pass next_cursor back as cursor to continue, and next_cursor is null on the last page. An empty candidates list is a valid result for a query nothing matches. One shape of candidate: {parcel: '5668018', addresses: ['237 CORTLAND AVE']}. Owner, occupant and tax data are never returned.
| Param | Type | Description |
|---|---|---|
| limit | integer | Maximum candidates per page; values above 50 are clamped to 50. |
| queryrequired | string | Address prefix (house number and street), street-name prefix, or block/lot prefix. Apostrophes are rejected. |
| cursor | string | Opaque continuation token copied from a previous response's next_cursor. Omit for the first page. |
{
"type": "object",
"fields": {
"query": "normalized (upper-cased) query that was searched",
"candidates": "array of parcel candidates: parcel (block/lot string, leading zeros and letter suffixes preserved), block, lot, addresses (array of recorded address strings), property_url (public property page)",
"next_cursor": "string token for the next page, or null when there are no more candidates"
},
"sample": {
"data": {
"query": "237 CORTLAND",
"candidates": [
{
"lot": "018",
"block": "5668",
"parcel": "5668018",
"addresses": [
"237 CORTLAND AVE"
],
"property_url": "https://sfplanninggis.org/pim/?search=5668018"
}
],
"next_cursor": null
},
"status": "success"
}
}About the Sfplanninggis API
Parcel Search and Identification
The search_properties endpoint accepts a query string — an address prefix like 237 Cortland, a street-name prefix, or a raw block/lot prefix like 1481001 — and returns an array of candidates. Each candidate includes the Assessor parcel identifier (4-digit block plus lot, with leading zeros and letter suffixes preserved), block, lot, all addresses recorded for that parcel, and a property_url pointing to the public property page. Results are paged via an opaque cursor token, and limit values above 50 are clamped to 50. Note that apostrophes in query strings are rejected.
Per-Parcel Evidence Records
Once you have a block/lot, get_property_evidence returns a flat, paged list of records for that parcel. Each record carries a source_id, a kind field (one of historical_photo, historic_survey, planning_document, or permit_record), a title, a source_url, and where available an asset_url for direct document access. The response also surfaces addresses, total_records, a property_url, and a warnings array that flags notable data gaps for the parcel. The limit parameter is capped at 200 records per page.
Citywide Historic Photo Collection
The list_property_photos endpoint pages the entire Historic Assessor's Photo PDF collection in stable ascending source object-ID order, making it practical to crawl or sync the full ~105,000-record dataset without querying parcels individually. An optional parcel_prefix filter (1–9 alphanumeric characters, case-insensitive) narrows results to photos whose filed block/lot text begins with that prefix. Each record in the records array has the same shape as a historical_photo from get_property_evidence, including source_id, kind, title, source_url, asset_url, and parcel. The total_records field reflects the source count before paging.
The Sfplanninggis API is a managed, monitored endpoint for sfplanninggis.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when sfplanninggis.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official sfplanninggis.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Resolve a San Francisco street address to its Assessor block/lot for downstream permit or zoning lookups.
- Download the full citywide Historic Assessor's Photo PDF dataset for urban history or machine-learning research using
list_property_photos. - Audit historic preservation survey coverage for a specific parcel by filtering
get_property_evidencerecords bykind: historic_survey. - Aggregate all planning application records linked to a given block/lot to track development activity over time.
- Build a neighborhood timeline by collecting
historical_photorecords for all parcels within a block prefix viaparcel_prefix. - Cross-reference building permit records from
get_property_evidencewith address data to identify properties with active permits. - Enumerate every recorded address variant for a parcel to support address normalization or deduplication pipelines.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does sfplanninggis.org offer an official developer API?+
What does `get_property_evidence` actually return, and how are the record kinds distinguished?+
records array where each item has a kind field set to one of four values: historical_photo (Historic Assessor photo PDFs), historic_survey (historic preservation survey entries), planning_document (planning application links), or permit_record (building permit entries). Every record also includes source_id, title, source_url, and optionally asset_url. The warnings field flags parcels where sections returned no data or had anomalies.Does the API cover parcels outside San Francisco?+
Does the API return current zoning classifications or land-use designations for a parcel?+
Are there any known limitations on the property search query format?+
search_properties endpoint performs a prefix match, so partial street names and block/lot prefixes work but mid-string substring queries do not. Apostrophes in query strings are explicitly rejected. Results are capped at 50 candidates per page regardless of the limit value supplied, and pagination requires copying the opaque next_cursor token from the previous response.