> ## Documentation Index
> Fetch the complete documentation index at: https://docs.propertylayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Make your first API call in about 5 minutes.

## Prerequisites

* An account. [Sign up](https://app.propertylayer.com) if you don't have one.
* An API key. See [Authentication](https://docs.propertylayer.com/guides/authentication.md) for how to create one.

***

## Step 1: Get your API key

1. Log in to the [dashboard](https://app.propertylayer.com).
2. Navigate to **API Keys** in the sidebar.
3. Click **Create key**, give it a name, and copy the key.

***

## Step 2: Find properties in an area

Call `POST /properties/area` with a GeoJSON FeatureCollection. PropertyLayer returns every property whose parcel geometry intersects your polygon.

```bash cURL theme={null}
curl -X POST https://api.propertylayer.com/properties/area \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "FeatureCollection",
    "features": [{
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-93.6250, 41.5868],
          [-93.6200, 41.5868],
          [-93.6200, 41.5830],
          [-93.6250, 41.5830],
          [-93.6250, 41.5868]
        ]]
      },
      "properties": {}
    }]
  }'
```

```python Python theme={null}
import httpx

API_KEY = "YOUR_API_KEY"
BASE = "https://api.propertylayer.com"

area_response = httpx.post(
    f"{BASE}/properties/area",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "type": "FeatureCollection",
        "features": [{
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [-93.6250, 41.5868],
                    [-93.6200, 41.5868],
                    [-93.6200, 41.5830],
                    [-93.6250, 41.5830],
                    [-93.6250, 41.5868],
                ]]
            },
            "properties": {}
        }]
    },
)
uuids = [p["bpd_uuid"] for p in area_response.json()["results"]]
print(uuids)
```

```javascript JavaScript theme={null}
const BASE = "https://api.propertylayer.com";
const API_KEY = "YOUR_API_KEY";

const areaRes = await fetch(`${BASE}/properties/area`, {
  method: "POST",
  headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    type: "FeatureCollection",
    features: [{
      type: "Feature",
      geometry: {
        type: "Polygon",
        coordinates: [[
          [-93.6250, 41.5868], [-93.6200, 41.5868],
          [-93.6200, 41.5830], [-93.6250, 41.5830],
          [-93.6250, 41.5868],
        ]],
      },
      properties: {},
    }],
  }),
});
const { results } = await areaRes.json();
const uuids = results.map((p) => p.bpd_uuid);
```

```json theme={null}
{
  "results": [
    {
      "bpd_uuid": "a1b2c3d4-…",
      "geoid": "19153",
      "ownership": { "owner_name": "SMITH JOHN A" },
      "land": { "acres": 2.47 },
      "…": "…"
    }
  ],
  "count": 3,
  "limit": 20,
  "offset": 0
}
```

> [!TIP]
>
> `limit` defaults to 20 and maxes out at 100. Page through larger areas with `offset`.

***

## Step 3: Fetch full records by UUID

Pass the UUIDs from Step 2 to `POST /properties/query` using the `in` operator. One call returns all records, each with its tax assessor detail already attached.

```bash cURL theme={null}
curl -X POST https://api.propertylayer.com/properties/query \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": [
      { "field": "bpd_uuid", "op": "in", "value": ["a1b2c3d4-…", "b2c3d4e5-…"] }
    ],
    "limit": 100
  }'
```

```python Python theme={null}
response = httpx.post(
    f"{BASE}/properties/query",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "filters": [{"field": "bpd_uuid", "op": "in", "value": uuids}],
        "limit": 100,
    },
)

for p in response.json()["results"]:
    owner = (p.get("ownership") or {}).get("owner_name")
    address = (p.get("situs_address") or {}).get("raw")
    acres = (p.get("land") or {}).get("acres")
    value = (p.get("valuation_current") or {}).get("total_value")
    print(owner, "|", address, "|", acres, "ac |", value)
```

```javascript JavaScript theme={null}
const queryRes = await fetch(`${BASE}/properties/query`, {
  method: "POST",
  headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    filters: [{ field: "bpd_uuid", op: "in", value: uuids }],
    limit: 100,
  }),
});
const { results } = await queryRes.json();
results.forEach((p) =>
  console.log(
    p.ownership?.owner_name,
    p.situs_address?.raw,
    p.land?.acres,
    p.valuation_current?.total_value,
  ),
);
```

```json theme={null}
{
  "results": [
    {
      "bpd_uuid": "c3dc1ad8…",
      "geoid": "06087",
      "identity": { "parcel_id": "04209215", "county_name": "Santa Cruz", "state": "CA" },
      "ownership": { "owner_name": "SMITH JOHN A" },
      "situs_address": { "raw": "152 SEACLIFF DR, APTOS , 95003-4443", "city": "APTOS", "zip": "95003" },
      "classification": { "land_use_description": "SINGLE RESIDENCE", "zoning": "R-1-4" },
      "land": { "acres": 0.099, "lot_sqft": 4312.0 },
      "building_summary": { "year_built": 1959, "bedrooms": 3, "baths_full": 2, "living_area_sqft": 1751 },
      "valuation_current": { "year": 2024, "basis": "assessed", "total_value": 1059906 },
      "cdl_majority_category": "Developed/Med Intensity",
      "fema_flood_zone": "X",
      "elevation": 32.0
    }
  ],
  "count": 1,
  "limit": 100,
  "offset": 0
}
```

***

## Step 4: Read valuation and sale history

`valuations` is the year-by-year assessment history and `transfers` is every recorded sale the assessor carries. `derived` has the roll-ups.

```python Python theme={null}
p = response.json()["results"][0]

for v in p.get("valuations") or []:
    print(v["year"], v.get("basis"), v.get("total_value"))

for t in p.get("transfers") or []:
    print(t.get("sale_date"), t.get("price"), t.get("instrument_type"))

derived = p.get("derived") or {}
print("last sale:", derived.get("last_sale_date"), derived.get("last_sale_price"))
```

```javascript JavaScript theme={null}
const p = results[0];
(p.valuations ?? []).forEach((v) => console.log(v.year, v.basis, v.total_value));
(p.transfers ?? []).forEach((t) => console.log(t.sale_date, t.price));
console.log("last sale:", p.derived?.last_sale_date, p.derived?.last_sale_price);
```

```json theme={null}
{
  "valuations": [
    { "year": 2024, "basis": "assessed", "total_value": 1059906 },
    { "year": 2025, "basis": "assessed", "total_value": 1081104 }
  ],
  "transfers": [
    { "sale_date": "2004-03-12", "price": 755000, "document_number": "2004-0015657" },
    { "sale_date": "1999-12-29", "price": 455000, "document_number": "1999-0080807" }
  ],
  "derived": { "last_sale_date": "2004-03-12", "last_sale_price": 755000 }
}
```

> [!NOTE]
>
> Sections are omitted when the county did not publish them, so guard your reads (`p.get("land") or {}`) rather than assuming every section is present.

***

## Next steps

> [card] [Query reference](https://docs.propertylayer.com/api-reference/query.md)
>
> All queryable fields and operators

> [card] [Data fields](https://docs.propertylayer.com/guides/data-fields.md)
>
> Full tax assessor field reference

> [card] [Data fields](https://docs.propertylayer.com/guides/data-fields.md)
>
> Full data dictionary

> [card] [Flat files](https://docs.propertylayer.com/guides/flat-files.md)
>
> Bulk data delivery for high-volume use cases


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.