191.3M US property records. RESTful JSON API with parcel search, owner intelligence, permits, deeds, and market analytics.
PropRaven is one verified parcel dataset delivered three ways — this REST API, a Snowflake Marketplace share, and bulk Parquet and CSV delivery — and the same record is byte-identical across all of them. The API is the right door when you need a parcel, an owner or a cohort inside an application: one HTTPS call returns the owner of record, assessed value, last sale, permits, deed history and hazard risk for any of the 191.3M parcels in the serving set, with an official client in Python, TypeScript and Go and a hosted Model Context Protocol server for AI agents.
The v1 surface is organised into the endpoint groups below — the tags of the published OpenAPI 3.1 specification, which currently describes 46 paths. Every response is JSON, every parcel is addressed by its composite county_fips:parcel_id identifier, and every record carries the serving epoch it was published from, so two callers asking for the same parcel on the same day get the same bytes.
| Group | What it returns |
|---|---|
| Parcels | One parcel by ID, plus its owner, permits, deed history, risk assessment, traffic history, GeoJSON polygons for a bounding box, and the paid dossier / comp pack / risk score. |
| Search | Parcel search by bounds, filters and sorting; full paginated text + attribute search; address / place / parcel autocomplete; CSV export of a result set. |
| Coverage | Coverage statistics — where PropRaven has parcel data, by state and county. |
| Deals | Absentee owners, flips, contractors by permit activity, entity-owned parcels, high land-to-improvement ratio, lender profiles, long-held parcels, portfolio owners, county-quarter transaction summaries. |
| Leads | A lead feed priced per lead, with a free masked preview of count, price and sample. |
| Market | County market statistics, a single-county detail view, market trends, and flip activity grouped by county. |
| Owners | Owner search by name, owner profile, the owner's properties, portfolio summary, recorded deed transactions, and the paid owner intelligence report. |
| Webhooks | Create, list, inspect and disable webhook endpoints, and read recent delivery attempts. |
| Account | Current-period usage and quota for your key. |
| Storefront | The sealed field catalog and try-before-buy availability quotes — the free discovery surface agents read first. |
| Credits | Fund and read a prepaid credit balance over x402. |
| Watch | Create a watch on a parcel or cohort (free) and poll it for new changes. |
| Verify | Verify facts for one parcel, or in batch, with a free preview. |
The Free plan is $0 with 1,000 lookups a month and no card required. New accounts land on /developers/welcome with the key on screen.
Include your API key in the Authorization header:
Authorization: Bearer pz_your_key_here
Keys are prefixed pz_ and are the only credential the API uses — there is no OAuth dance for server-to-server calls, and the same key authenticates the SDKs and the hosted MCP server. A key is required on every endpoint except the free discovery surface (coverage statistics, the storefront catalog and availability quotes, and lead-feed previews) and the x402-paid resources, which accept a signed wallet payment instead of a key. Being authenticated is not the same as being entitled: a free-tier key asking for a paid dossier gets the same HTTP 402 an anonymous caller does.
Keys are created and revoked self-serve under Settings > API Keys. Treat them as secrets — never ship one in a browser bundle. For the supply-chain side (SLSA provenance on every SDK and MCP release, OIDC trusted publishing) see Security.
The raw HTTP surface needs nothing but a key. The single-parcel lookup below is the first call most integrations make; the ID is the composite county FIPS and assessor parcel number.
curl -H "Authorization: Bearer pz_your_key" \
"https://api.propraven.com/v1/parcels/37183:0429966"import requests
resp = requests.get(
"https://api.propraven.com/v1/parcels/37183:0429966",
headers={"Authorization": "Bearer pz_your_key"}
)
parcel = resp.json()
print(parcel["address"], parcel["total_assessed_value"])const res = await fetch(
"https://api.propraven.com/v1/parcels/37183:0429966",
{ headers: { Authorization: "Bearer pz_your_key" } }
);
const parcel = await res.json();
console.log(parcel.address, parcel.total_assessed_value);All three clients are generated from the same OpenAPI 3.1 document via Stainless, so method names mirror the REST paths (client.v1.parcels.retrieve is GET /api/v1/parcels/{id}) and a fix to the spec ships to every language at once. Each release carries a SLSA provenance attestation signed by GitHub Actions OIDC and recorded in the Sigstore transparency log; the source is public at jdw2111/propraven-python, jdw2111/propraven-typescript and jdw2111/propraven-go. Every client reads PROPRAVEN_API_KEY from the environment by default.
pip install propravenfrom propraven import Propraven
client = Propraven() # reads PROPRAVEN_API_KEY from env
# Single parcel
parcel = client.v1.parcels.retrieve("37183:0012345")
print(parcel.owner_name, parcel.assessed_value)
# Owner pierce
portfolio = client.v1.owners.retrieve_portfolio_summary("BLACKROCK FUND ADVISORS")
# Coverage stats
cov = client.v1.retrieve_coverage()
print(f"{cov.total_parcels:,} parcels across {cov.states_covered} states")Python 3.9+. An AsyncPropraven client and propraven[pandas] / propraven[polars] / propraven[arrow] extras for DataFrame conversion are included.
npm install @propraven/sdkimport Propraven from "@propraven/sdk";
const client = new Propraven({
apiKey: process.env.PROPRAVEN_API_KEY!,
});
// Single parcel
const parcel = await client.v1.parcels.retrieve("37183:0012345");
console.log(parcel.owner_name, parcel.assessed_value);
// Owner pierce
const portfolio = await client.v1.owners.retrievePortfolioSummary("BLACKROCK FUND ADVISORS");
// Coverage stats
const cov = await client.v1.retrieveCoverage();
console.log(`${cov.total_parcels.toLocaleString()} parcels across ${cov.states_covered} states`);Node 18+, modern browsers, Deno, Cloudflare Workers, Bun. ESM + CJS dual export, with a verifyWebhook helper built on Web Crypto.
go get github.com/jdw2111/propraven-go@latestpackage main
import (
"context"
"fmt"
"log"
"os"
"github.com/jdw2111/propraven-go"
"github.com/jdw2111/propraven-go/option"
)
func main() {
client := propraven.NewClient(
option.WithAPIKey(os.Getenv("PROPRAVEN_API_KEY")),
)
ctx := context.Background()
parcel, err := client.V1.Parcels.Get(ctx, "06037:1234-567-890")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", parcel.ParcelID)
}Go 1.22+. The client retries 429s and idempotent 5xx by default; everything sits under client.V1.* to mirror the REST paths.
Plans are metered on lookups per month; that monthly cap is the enforced meter, and a per-key burst limit sits on top of it. The four tiers below are the same ladder the pricing page publishes.
| Tier | Lookups | Price | Includes |
|---|---|---|---|
| Free | 1,000 / mo | $0 | Full records in the web app, self-serve API keys. No card required. |
| Developer | 100,000 / mo | $99/mo · 14-day free trial | Full API, SDKs & webhooks, MCP connector, owner & sponsor graph. |
| Team | 1,000,000 / mo | $1,000/mo | Everything in Developer, bulk export, priority support. |
| Data license | Unmetered (bulk) | Custom | Full state or national tables via Snowflake, Databricks or Parquet. Annual license, invoiced. |
Unauthenticated responses and every 429 carry the rate-limit headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Read your current-period consumption from GET /api/v1/account/usage. Sustained throughput above the Team cap, or whole-state and national tables, is the data license path rather than a bigger meter.
The API has a second front door built for software that reasons rather than renders. The hosted Model Context Protocol server at mcp.propraven.com exposes 31 typed tools — parcel lookup, search and compare, owner pierce, hazard score, valuation estimate, permit and sales history, the deal finders, and the storefront pair — to Claude Desktop, Claude Code, Cursor, ChatGPT and any MCP-compatible client. The same pz_ key authenticates it as a bearer header; the claude.ai web connector uses OAuth instead. A local @propraven/mcp package on npm speaks stdio for latency-sensitive work. Setup for each client is on the MCP page, which is generated from the live tool registry.
{
"mcpServers": {
"propraven": {
"url": "https://mcp.propraven.com/",
"headers": { "Authorization": "Bearer pz_your_real_key_here" }
}
}
}Agents that arrive with a wallet instead of an account use x402. The flow is discover → preview → pay: 2 tools (get_catalog and check_availability) are free and return the sealed field catalog with measured per-state coverage and the exact price of a specific parcel's dossier before anything is spent. Requesting the paid resource without payment returns HTTP 402 with the precise USDC-on-Base amount to sign; sign an EIP-3009 transferWithAuthorization, retry with the X-PAYMENT header, and the 200 carries the dossier plus an on-chain settlement receipt. A failed build is never charged. The dossier price is value-tiered and auditable — clamp($5 × V × R × F, $2, $20) — and lead feeds, owner reports, comp packs and risk scores follow the same 402 contract. The full walkthrough is on Connect your agent.
Every endpoint reads the same serving set the warehouse shares and the web app render: 191.3M parcels · 110.0M mapped at the 2026-08-30 epoch, 620 columns per parcel, 51 states (all 50 plus DC). The joined facts include 180M+ building permits, 10M+ title transfers, 27M+ resolved owners and 143M+ addresses; 110.0M distinct locations carry a coordinate the map can draw. Coverage is uneven by design of the sources — county assessors, recorders and permit offices publish different fields — so check GET /api/v1/coverage or the storefront catalog for the jurisdiction you care about rather than trusting a national average. The data page publishes live counts, the schema explorer and per-field fill rates; parcel data explains what a parcel record contains.
Twelve of the 46 paths in the spec, as a map of the territory. Paths are relative to https://api.propraven.com.
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/parcels/{id} | Get parcel by ID | API key |
| GET | /api/v1/parcels/{id}/owner | Get parcel owner details and portfolio | API key |
| GET | /api/v1/parcels/{id}/permits | Get parcel permits | API key |
| GET | /api/v1/parcels/{id}/deeds | Get parcel deed history | API key |
| POST | /api/v1/search | Search parcels by bounds, filters, and sorting | API key |
| GET | /api/v1/search/export | Export search results as CSV | API key |
| GET | /api/v1/coverage | Get coverage statistics | None |
| GET | /api/v1/deals/absentee | Find absentee owners | API key |
| GET | /api/v1/owners/{name}/portfolio | Get owner portfolio summary | API key |
| GET | /api/v1/storefront/catalog | Machine Storefront — sealed field catalog | None |
| GET | /api/v1/parcels/{id}/report | Parcel dossier (paid, provenance-first) | Key or x402 |
| GET | /api/v1/account/usage | Current-period usage and quota | API key |
Polling is the wrong shape for change detection across 191.3M parcels, so the API pushes. Register an endpoint with POST /api/v1/webhooks and PropRaven delivers parcel.sold, parcel.permit_filed and parcel.owner_changed events signed with HMAC-SHA256 in the X-PropRaven-Signature header; each event carries a deterministic event_id for idempotency and the SDKs ship a constant-time verifier with a five-minute replay window. Payload schemas and delivery semantics are on the webhooks page.
Errors return a JSON object with an error field:
{
"error": "Invalid API key"
}| Status | Meaning |
|---|---|
| 400 | Bad request (missing or invalid parameters) |
| 401 | Invalid or missing API key |
| 402 | Payment required — the body is an x402 offer naming the exact amount |
| 403 | API key is inactive or expired |
| 404 | Resource not found |
| 429 | Rate limit exceeded (check Retry-After header) |
| 500 | Internal server error |
The full OpenAPI specification is available at /openapi.json. Import it into Postman, Insomnia, or any OpenAPI-compatible tool, or point a ChatGPT Custom GPT Action at it with Bearer authentication.