> ## 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.

# Query properties

## Request format

Pass a `filters` array where each item specifies a `field`, an `op` (operator), and a `value`. All filters are AND'd together.

```json theme={null}
{
  "filters": [
    { "field": "owner", "op": "ilike", "value": "SMITH" },
    { "field": "state", "op": "eq", "value": "CA" }
  ],
  "limit": 20,
  "offset": 0
}
```

Use an array value for `in`, `nin`, and `between`:

```json theme={null}
{
  "filters": [
    { "field": "state", "op": "in", "value": ["CA", "OR", "WA"] },
    { "field": "acres", "op": "between", "value": [500, 10000] }
  ]
}
```

## Queryable fields

The fields below are the ones you can filter on. Everything else on a property comes back on every response but cannot be filtered. See [Data fields](/guides/data-fields).

### Text search fields: `ilike`, `eq`, `ne`, `in`, `nin`, `isnull`

`ilike` is a case-insensitive whole-word match, not a substring match. Searching `SMIT` will not find `SMITH`; it finds records containing the word `SMIT`. Multiple words are AND'd, so `SMITH JOHN` matches records containing both.

| Field | Description |
| - | - |
| `owner` | Owner name |
| `parcel_id` | County assessor parcel number (APN). See [Looking up an APN](#looking-up-an-apn) |
| `situs` | Property address |
| `mail_addr` | Owner mailing address |
| `city` | City |
| `land_use` | Land use classification |
| `land_use_code` | Land use code |
| `legal` | Legal description |
| `county` | County name |
| `zoning` | Zoning code |
| `cdl_majority_category` | USDA crop/land cover type (e.g. `Corn`, `Soybeans`) |

### Numeric fields: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `between`, `in`, `nin`, `isnull`

| Field | Description |
| - | - |
| `acres` | Parcel area (county-reported) |
| `acres_calc` | Parcel area (calculated from geometry) |
| `parcel_value` | Total assessed value (USD) |
| `land_value` | Land assessed value (USD) |
| `improvements_value` | Improvements assessed value (USD) |
| `agricultural_value` | Agricultural assessed value (USD) |
| `building_value` | Building assessed value (USD) |
| `sale_price` | Most recent sale price (USD) |
| `tax_amount` | Annual property tax (USD) |
| `elevation` | Centroid elevation (meters) |
| `adjacent_acreage_sameowner` | Contiguous acreage under same ownership |
| `cdl_majority_value` | Numeric CDL category code |
| `cdl_majority_percent` | % of parcel covered by majority CDL category |
| `sq_feet` | Parcel area in square feet |

### ID and categorical fields: `eq`, `ne`, `in`, `nin`, `isnull`

| Field | Description |
| - | - |
| `state_fp` | State FIPS code (e.g. `"19"` for Iowa) |
| `state` | Two-letter state abbreviation (e.g. `"IA"`) |
| `county_fp` | County FIPS code |
| `postal` | ZIP code |
| `owner_type` | Owner type |
| `sale_date` | Sale date string |
| `bpd_uuid` | PropertyLayer UUID; use `in` to batch-fetch records from an area search |
| `bpd_stack_uuid` | Stack UUID for grouped same-location properties |

## Looking up an APN

Counties print the same parcel number many ways. `0385`, `385`, `0-385` and
`004-201-034-000` are all spellings you might find on a tax bill or a county
portal. Send whichever one you have.

```json theme={null}
{ "filters": [{ "field": "parcel_id", "op": "eq", "value": "0385" }] }
```

PropertyLayer reduces both your input and the stored value to one canonical form before
comparing: separators and whitespace are dropped, letters are uppercased, and
leading zeros are removed. So `0385`, `385` and `0-385` all resolve to the same
parcel.

The comparison is exact, never fuzzy. A partial number does not return the
parcels that happen to contain it, so a lookup gives you the parcel you asked
for or nothing at all. `eq`, `ne`, `in` and `nin` all behave this way.

> [!NOTE]
>
> Interior zeros are part of the number and are preserved. Only leading padding
> is removed, so `100` and `1` remain different parcels.

## Operators

| Operator | Description | Value type |
| - | - | - |
| `eq` | Equals | string or number |
| `ne` | Not equals | string or number |
| `gt` / `gte` | Greater than (or equal) | number |
| `lt` / `lte` | Less than (or equal) | number |
| `between` | Inclusive range | 2-element array: `[min, max]` |
| `in` | In set | array of strings or numbers |
| `nin` | Not in set | array of strings or numbers |
| `ilike` | Case-insensitive whole-word match (words are AND'd) | string |
| `isnull` | Is null / is not null | `true` (null) or `false` (not null) |

## Sorting

Pass an optional `order` object with a `field` and `direction`:

```json theme={null}
{
  "filters": [{ "field": "state_fp", "op": "eq", "value": "19" }],
  "order": { "field": "acres", "direction": "desc" }
}
```

## Pagination

Use `limit` (max 100, default 20) and `offset` to page through results. `offset + limit` must not exceed 10,000; beyond that, narrow the filters rather than paging deeper.

```json theme={null}
{
  "filters": [
    { "field": "state_fp", "op": "eq", "value": "19" },
    { "field": "acres", "op": "gte", "value": 100 }
  ],
  "limit": 100,
  "offset": 200
}
```

## Tax assessor data

The county tax assessor record comes back as top-level sections on every property: `ownership`, `situs_address`, `classification`, `land`, `building_summary`, `buildings`, `valuation_current`, `valuations`, `taxes`, `exemptions`, `transfers` and `derived`. No flag required.

These sections are not filterable, and a filter name is not always the path it reads back as: you filter on `owner` and read the result back as `ownership.owner_name`. See [Data fields](/guides/data-fields) for the full field reference.

## Building footprints

Set `include_buildings: true` to attach ORNL footprint geometry as a `building_footprints` array.

```json theme={null}
{
  "filters": [{ "field": "state_fp", "op": "eq", "value": "06" }],
  "include_buildings": true
}
```

Each entry includes footprint geometry (`geom`), `height`, `height_variance`, and `estimated_floors`. The key is omitted entirely when `include_buildings` is `false` (the default).

> [!NOTE]
>
> `include_buildings` returns footprint geometry under `building_footprints`. Construction detail such as bedrooms, baths, roof, HVAC and year built lives in the assessor's `buildings` array and `building_summary`, which are always present where an assessor record exists.

## Response

Every endpoint returns the same object. The [Property model](/api-reference/property-model) has the full field reference: tax assessor sections, parcel geometry, and enrichments.


## OpenAPI

````yaml POST /properties/query
openapi: 3.1.0
info:
  title: PropertyLayer API
  description: >-
    Access nationwide property data — parcel boundaries, tax assessor records,
    and building footprints — by geographic polygon, point, or address.
  version: 1.0.0
servers:
  - url: https://api.propertylayer.com
    description: Production
security: []
paths:
  /properties/query:
    post:
      tags:
        - properties
      summary: Query Properties Post
      operationId: query_properties_post_properties_query_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PropertyQueryRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                description: >-
                  A Property object. See the Property model for the full
                  response shape — tax assessor sections, parcel geometry, and
                  enrichment fields.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                type: object
                description: >-
                  A Property object. See the Property model for the full
                  response shape — tax assessor sections, parcel geometry, and
                  enrichment fields.
      security:
        - HTTPBearer: []
components:
  schemas:
    PropertyQueryRequest:
      properties:
        filters:
          items:
            $ref: '#/components/schemas/FilterItem'
          type: array
          maxItems: 10
          title: Filters
        order:
          anyOf:
            - $ref: '#/components/schemas/OrderItem'
            - type: 'null'
        limit:
          type: integer
          maximum: 100
          minimum: 1
          title: Limit
          default: 20
        offset:
          type: integer
          maximum: 10000
          minimum: 0
          title: Offset
          default: 0
        include_buildings:
          type: boolean
          title: Include Buildings
          default: false
      type: object
      required:
        - filters
      title: PropertyQueryRequest
    FilterItem:
      properties:
        field:
          type: string
          title: Field
        op:
          type: string
          title: Op
        value:
          anyOf:
            - type: string
            - type: integer
            - type: number
            - type: boolean
            - items:
                anyOf:
                  - type: string
                  - type: integer
                  - type: number
              type: array
            - type: 'null'
          title: Value
      type: object
      required:
        - field
        - op
      title: FilterItem
    OrderItem:
      properties:
        field:
          type: string
          title: Field
        direction:
          type: string
          enum:
            - asc
            - desc
          title: Direction
          default: asc
      type: object
      required:
        - field
      title: OrderItem
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````

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