One property API · Developer preview

Build commercial property apps with county data.

Search properties, retrieve building and assessment facts, and show where the information came from—through one documented API.

Hosted access is invitation-only. Sign in when you are ready to connect live data. No billing is active.

CRE LAYER / PROPERTY RECORD
  1. 01
    Identity

    County + parcel. Stable across refreshes.

  2. 02
    Official facts

    Use, structures, assessment, recorded sales.

  3. 03
    Source evidence

    Original fields, artifacts, dates and hashes.

Illustrative record structure. Fields vary by county.
Search onceConsistent county + parcel IDsTraceable source evidenceHTTP · MCP

What you can build today

Property experiences grounded in county records.

The current API keeps source-reported facts, CRE Layer normalization and missing-data signals distinct. Field availability varies by county.

Two markets. Local evidence.

Building depth in Seattle and Miami.

Check current availability →
WA / 01

Seattle metro

King · Pierce · Snohomish

Launch focus · private preparation
FL / 02

Miami metro

Broward · Miami-Dade · Palm Beach

Launch focus · private preparation

These six counties define our launch focus. Availability depends on the configured API's validated datasets. County use-code coverage varies; Florida's 2026 assessments are preliminary. This is not a public coverage promise.

Built for your workflow

One connection for facts and evidence.

Full quickstart →

Use one personal key and the configured endpoint across HTTP and MCP. Always check live coverage before requesting a property.

01 / HTTP

A small, explicit API

# Check the configured API's coverage
curl -H "Authorization: Bearer $CRELAYER_API_KEY" \
  "https://crelayer.com/data/counties"

# Search one county; missing fields stay explicit. Every result row embeds a
# property-scoped context and the response carries contextSummary.
curl -H "Authorization: Bearer $CRELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"countyIds":["us-wa-king"],"filters":{"text":"Market"},"limit":3}' \
  "https://crelayer.com/data/properties:query"

# Read the ordinary property detail; it embeds the same context.
curl -H "Authorization: Bearer $CRELAYER_API_KEY" \
  "https://crelayer.com/data/counties/us-wa-king/properties/YOUR_PARCEL_ID"

# Optional: the standalone context route returns just the point facts.
# NAIP is catalog metadata only; FEMA describes the queried point only.
curl -H "Authorization: Bearer $CRELAYER_API_KEY" \
  "https://crelayer.com/data/counties/us-wa-king/properties/YOUR_PARCEL_ID/context"
02 / TYPESCRIPT

Use it from your server

// Server-side JavaScript / TypeScript; never embed a key in a browser.
// Keep any base path prefix, for example a gateway at https://api.example/data.
const baseUrl = (process.env.CRELAYER_API_BASE_URL ?? "https://crelayer.com/data")
  .replace(/\/+$/u, "");
const key = process.env.CRELAYER_API_KEY;
if (!key) throw new Error("Configure a private API key first");

// Prefix-safe: new URL("/counties", "https://api.example/data") drops /data.
function apiUrl(path: string): URL {
  const url = new URL(baseUrl);
  url.pathname = `${url.pathname.replace(/\/+$/u, "")}${path}`;
  return url;
}

async function read(path: string, init: RequestInit = {}) {
  const response = await fetch(apiUrl(path), {
    ...init,
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
  });
  if (!response.ok) throw new Error(`CRE Layer returned HTTP ${response.status}`);
  return response.json();
}

const result = await read("/properties:query", {
  method: "POST",
  body: JSON.stringify({
    countyIds: ["us-wa-king"], filters: { text: "Market" }, limit: 3,
  }),
});
// Inspect result.counties: a county may be not_evaluable or not_covered.
const first = result.results[0];
if (!first) throw new Error("No covered parcel matched this query");
const path = `/counties/${encodeURIComponent(first.countyId)}/properties/${encodeURIComponent(first.parcelId)}`;
const detail = await read(path);
const evidence = await read(`${path}/provenance`);
// detail.missingFields and detail.dataset describe limits and freshness.

// Point context is embedded in every query row and in the detail response, so
// no extra call is needed. The batch metadata reports bounded attempts; a row
// context is "available" | "unavailable", and a missing coordinate is available
// with point: null and both modules not_evaluable. NAIP is catalog metadata
// only; FEMA describes the queried point only.
const rowContext = first.context;
const batch = result.contextSummary;
const detailContext = detail.context;

Keep credentials in server-side secret storage, never in browser code.

03 / MCP

Give your agent evidence

{
  "mcpServers": {
    "crelayer": {
      "url": "https://crelayer.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_CRELAYER_API_KEY"
      }
    }
  }
}

Use the hosted MCP endpoint and a personal key from your invited account.

Coverage, without guesswork

What this API serves right now

The API currently serves 6 counties in private preview totaling 150,831 properties. Only the live coverage matrix is authoritative.

County details, source dates and limitations →

Know what you are building on

Useful facts. Visible limits.

Point context · facts only

Two official sources, honest boundaries.

For a served parcel with a published coordinate, the context route adds point-context facts from two official sources. Each is a source observation for the queried point with its own dates, units, method, provenance and caveats—never a risk score.

USGS NAIP catalog metadata

Catalog identity, acquisition date, ground-sample distance in meters, band count, sensor, projection and datum for imagery intersecting the queried point.

Boundary: Catalog metadata only. It is not imagery, image bytes, asset URLs, current property condition or property-condition evidence, and a point intersection does not establish imagery coverage for the whole parcel.

FEMA National Flood Hazard Layer

Flood zone, subtype, special-flood-hazard flag, base-flood elevation, depth and velocity with units, and FIRM panel preliminary and effective dates for the queried point.

Boundary: Describes the queried point only. It is not parcel-wide flood risk, and not insurance, safety, survey, engineering or an official map determination; an empty response does not mean no flood risk.

GET /counties controls served parcel identity and county field availability. Point-context module availability is not a county field: the per-module status on each embedded or standalone context is authoritative. The same context is embedded in every query result row and in property detail, so the standalone /context route is optional; a row keeps its facts when context is unavailable, missing coordinates are never geocoded, and rows not attempted because the per-response cap or the overall budget was reached are explicitly batch_row_limit or batch_budget_exceeded respectively. Point context is authorized only for us-wa-king, us-wa-pierce, us-wa-snohomish, us-fl-broward, us-fl-miami-dade, us-fl-palm-beach; elsewhere both modules return not_evaluable with reason geography_not_authorized, and a parcel without a published coordinate returns coordinates_not_published. A module is observed, not_found, not_evaluable or unavailable; one module failing upstream leaves the other intact. No owner, mailing, tenant or party fields, no imagery bytes or asset URLs, no source geometry and no raw arbitrary upstream URLs are returned.

Build on today's API

Start with the current contract.

Read the exact routes, check coverage, then connect a personal key after invitation.

Read developer docs →