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

# Search Properties

Search the DealMachine property database using filters. Control which fields are returned, how results are paginated and sorted, and whether contacts are included.

## Body Parameters

<ParamField body="locations" type="array">
  Array of [location objects](/concepts/locations) defining where to search. Required unless filters or protocol filters are provided (max 15). Locations use **OR** logic — results matching any location are included.

  <Expandable title="Location object properties">
    <ParamField body="type" type="string" required>
      Location type: `state`, `county`, `city`, `zip_code`, `radius`, or `polygon`.
    </ParamField>

    <ParamField body="code" type="string">
      Location identifier. Required for `state` (2-letter abbreviation, e.g., `"TX"`), `county` (5-digit FIPS code, e.g., `"29189"`), `city` (place ID, e.g., `"7333"`), and `zip_code` (5-digit ZIP, e.g., `"63101"`).
    </ParamField>

    <ParamField body="latitude" type="number">
      Center point latitude. Required for `radius`.
    </ParamField>

    <ParamField body="longitude" type="number">
      Center point longitude. Required for `radius`.
    </ParamField>

    <ParamField body="radius_miles" type="number">
      Search radius in miles. Required for `radius`.
    </ParamField>

    <ParamField body="coordinates" type="array">
      Array of `[longitude, latitude]` pairs defining the boundary. Required for `polygon` (minimum 3 points).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="filters" type="array">
  Array of [filter objects](/concepts/filter-values). Required unless locations or protocol filters are provided. You can mix property filters (`source_type=properties`) and people filters (`source_type=people`).

  <Expandable title="Filter object properties">
    <ParamField body="filter_id" type="string" required>
      The filter slug from the [List Filters](/api-reference/filters/list-filters) endpoint (e.g., `estimated_value`, `property_type_id`).
    </ParamField>

    <ParamField body="operator" type="string">
      One of the filter's `allowed_operators`. See [Filter Values](/concepts/filter-values) for all operators by type. **Optional for BOOLEAN filters** — automatically defaults to `is_boolean`.
    </ParamField>

    <ParamField body="value" type="any" required>
      The filter value. Shape depends on the operator — can be a number, string, boolean, array, or object. See [Filter Values](/concepts/filter-values).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="include_lists" type="object">
  Restrict results to property list IDs, for example `{ "property_list_ids": [123] }`.
</ParamField>

<ParamField body="exclude_lists" type="object">
  Exclude property list IDs, for example `{ "property_list_ids": [456] }`.
</ParamField>

<ParamField body="exclude_previously_exported" type="boolean | object">
  Exclude records already exported by your organization. Pass `true` for defaults or a full Query
  Builder export exclusion object.
</ParamField>

<ParamField body="bigquery_data_environment" type="integer">
  Query Builder dataset environment: `1` production, `2` staging, `3` development.
</ParamField>

<ParamField body="fields" type="string[]">
  [Field IDs](/concepts/fields) to include in results. Can include both property and people fields.
  Omit or pass an empty array for the default set. With `anchor: "people"`, property address/context
  fields do not add property credits. Other property output fields do.
</ParamField>

<ParamField body="anchor" type="string" default="properties">
  Controls the shape of the response.

  Use `properties` to return properties with contacts nested in a `contacts` array. See [Anchor Behavior](#anchor-behavior). Use `people` to return people with a `residence` and associated `property`; this requires `contact_audience`.
</ParamField>

<ParamField body="contact_audience" type="string" default="owners">
  Which contacts to include. **Required** when `anchor` is `people`. Defaults to `"owners"` when `anchor` is `"properties"`.

  Options: `owners`, `owners_and_family`, `renters`, `residents`, `none`

  Set to `"none"` to explicitly opt out of contacts. Returned contacts consume people credits in addition to property credits.
</ParamField>

<ParamField body="page" type="integer" default={1}>
  Page number (min: `1`).
</ParamField>

<ParamField body="per_page" type="integer" default={25}>
  Results per page (min: `1`, max: `250`).
</ParamField>

<ParamField body="sort" type="array">
  Array of sort objects for ordering results. See [Pagination & Sorting](/concepts/pagination#sorting).

  <Expandable title="Sort object properties">
    <ParamField body="field_id" type="string" required>
      The field to sort by.
    </ParamField>

    <ParamField body="direction" type="string" required>
      `asc` (ascending) or `desc` (descending).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="estimate_cost" type="boolean" default={false}>
  When `true`, returns a credit cost estimate **without returning data or consuming credits**. See
  [Cost Estimate](#cost-estimate).
</ParamField>

***

<RequestExample>
  ```bash Search theme={null}
  curl -X POST "https://api.v2.dealmachine.com/v1/properties/search" \
    -H "Authorization: Bearer dm_sk_live_xxx" \
    -H "Content-Type: application/json" \
    -d '{
      "locations": [
        { "type": "county", "code": "48201" },
        { "type": "county", "code": "48113" }
      ],
      "anchor": "properties",
      "contact_audience": "owners",
      "filters": [
        {
          "filter_id": "estimated_value",
          "operator": "range",
          "value": { "min": 200000, "max": 600000 }
        },
        {
          "filter_id": "has_absentee_owners",
          "value": true
        }
      ],
      "fields": [
        "estimated_value",
        "equity_percent",
        "bedrooms"
      ],
      "page": 1,
      "per_page": 25,
      "sort": [
        { "field_id": "estimated_value", "direction": "desc" }
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "data": [
      {
        "dm_property_id": "prop_a1b2c3",
        "full_address": "1200 Barton Springs Rd, Austin, TX 78704",
        "address": "1200 Barton Springs Rd",
        "unit": null,
        "city": "Austin",
        "state": "TX",
        "zip": "78704",
        "latitude": 30.2598,
        "longitude": -97.7544,
        "images": {
          "street_view": "https://next.v3.dealmachine.com/map/streetview?...",
          "satellite": "https://next.v3.dealmachine.com/map/satellite?...",
          "roadmap": "https://next.v3.dealmachine.com/map/staticmap?..."
        },
        "estimated_value": 575000,
        "equity_percent": 72,
        "num_bedrooms": 4,
        "num_bathrooms": 2,
        "living_area_sqft": 2200,
        "contacts": [
          {
            "dm_person_id": "per_67890",
            "full_name": "John Smith",
            "first_name": "John",
            "last_name": "Smith",
            "is_likely_owner": true,
            "is_in_owner_family": false,
            "is_resident": true,
            "is_likely_renter": false,
            "phones": [{ "number": "5125551234", "type": "wireless", "do_not_call": false }],
            "emails": [{ "address": "john.smith@example.com" }]
          }
        ]
      }
    ],
    "totals": {
      "properties": 1847,
      "people": 2134
    },
    "credits": {
      "used": 50,
      "properties": 25,
      "people": 25,
      "deduplicated": 0
    },
    "pagination": {
      "page": 1,
      "per_page": 25,
      "total_results": 1847,
      "total_pages": 74,
      "has_next_page": true,
      "has_previous_page": false
    }
  }
  ```
</ResponseExample>

## Response

Every search response contains three top-level keys: `data`, `totals`, and `pagination`.

### `data`

An array of result objects. The shape depends on the `anchor` parameter.

Each property includes its standard response fields plus any requested `fields`. Contacts include
phones, emails, and DNC status. Credits are consumed per returned entity type.

When `anchor` is `"properties"` (the default), each object is a property. Every property includes the [always-included fields](/concepts/response-format#always-included-fields) — address, coordinates, and signed image URLs — plus any fields you requested and, optionally, a `contacts` array.

```json theme={null}
{
  "dm_property_id": "prop_a1b2c3",
  "full_address": "1200 Barton Springs Rd, Austin, TX 78704",
  "address": "1200 Barton Springs Rd",
  "unit": null,
  "city": "Austin",
  "state": "TX",
  "zip": "78704",
  "latitude": 30.2598,
  "longitude": -97.7544,
  "images": {
    "street_view": "https://next.v3.dealmachine.com/map/streetview?...",
    "satellite": "https://next.v3.dealmachine.com/map/satellite?...",
    "roadmap": "https://next.v3.dealmachine.com/map/staticmap?..."
  },
  "estimated_value": 575000,
  "equity_percent": 72,
  "num_bedrooms": 4,
  "num_bathrooms": 2,
  "living_area_sqft": 2200,
  "contacts": [
    {
      "dm_person_id": "per_67890",
      "full_name": "John Smith",
      "first_name": "John",
      "last_name": "Smith",
      "is_likely_owner": true,
      "is_in_owner_family": false,
      "is_resident": true,
      "is_likely_renter": false,
      "phones": [{ "number": "5125551234", "type": "wireless", "do_not_call": false }],
      "emails": [{ "address": "john.smith@example.com" }]
    }
  ]
}
```

When `anchor` is `"people"`, each object is a person. The person's residence (where they live) is in a `residence` object, and the associated property is nested in a `property` object. See [Anchor Behavior](#anchor-behavior) for details.

```json theme={null}
{
  "dm_person_id": "per_150468071288",
  "full_name": "Craig Heller",
  "first_name": "Craig",
  "last_name": "Heller",
  "phones": [
    { "number": "5125551234", "type": "wireless", "do_not_call": true },
    { "number": "5125559876", "type": "landline", "do_not_call": false }
  ],
  "emails": [
    { "address": "craig@example.com" }
  ],
  "residence": {
    "address": "315 N 11TH ST",
    "unit": "APT 1203",
    "city": "SAINT LOUIS",
    "state": "MO",
    "zip": "63101",
    "full_address": "315 N 11TH ST APT 1203, SAINT LOUIS, MO 63101"
  },
  "property": {
    "dm_property_id": "prop_80365658",
    "full_address": "316 N 8TH ST, SAINT LOUIS, MO 63101",
    "address": "316 N 8TH ST",
    "unit": null,
    "city": "SAINT LOUIS",
    "state": "MO",
    "zip": "63101",
    "latitude": 38.63026,
    "longitude": -90.193701,
    "images": { "..." },
    "estimated_value": 305000
  }
}
```

### `contacts`

The `contacts` array is present on each property when `contact_audience` is set to a value other than `"none"` (default: `"owners"`).

| Field                | Type           | Description                                            |
| -------------------- | -------------- | ------------------------------------------------------ |
| `dm_person_id`       | string         | DealMachine person ID                                  |
| `full_name`          | string         | Full display name                                      |
| `first_name`         | string \| null | First/given name                                       |
| `last_name`          | string \| null | Last/family name                                       |
| `is_likely_owner`    | boolean        | Whether this person is likely the owner                |
| `is_in_owner_family` | boolean        | Whether this person is in the owner's family           |
| `is_resident`        | boolean        | Whether this person is a resident                      |
| `is_likely_renter`   | boolean        | Whether this person is likely a renter                 |
| `phones`             | array          | Phone numbers with `number`, `type`, and `do_not_call` |
| `emails`             | array          | Email addresses with `address`                         |

### `totals`

The full count of matching entities across the entire result set, regardless of pagination.

```json theme={null}
{
  "totals": {
    "properties": 1847,
    "people": 2134
  }
}
```

| Field        | Type    | Description                                              |
| ------------ | ------- | -------------------------------------------------------- |
| `properties` | integer | Total properties matching the filters                    |
| `people`     | integer | Total people matching the filters and `contact_audience` |

### `pagination`

| Field               | Type    | Description                             |
| ------------------- | ------- | --------------------------------------- |
| `page`              | integer | Current page number                     |
| `per_page`          | integer | Results per page                        |
| `total_results`     | integer | Total matching records                  |
| `total_pages`       | integer | Total pages available                   |
| `has_next_page`     | boolean | Whether more pages exist after this one |
| `has_previous_page` | boolean | Whether pages exist before this one     |

***

## Anchor Behavior

The `anchor` parameter controls the response shape and how mixed filters are applied.

### `anchor: "properties"` (default)

Results are **properties**. Contacts matching the `contact_audience` are nested in a `contacts` array on each property.

* **Property filters** determine which properties are returned.
* **People filters** scope the `contacts` array on each property — they do **not** filter out properties. A property is still returned even if no contacts match.
* **People fields** you request appear on each object in the `contacts` array.
* If `contact_audience` is `"none"`, no `contacts` array is included. Default is `"owners"`.
* Billing is 1 property data credit per property. Nested contacts consume people credits.

### `anchor: "people"`

Results are **people**. The `contact_audience` parameter is **required**.

* **Property filters** determine which properties to search within.
* **People filters** determine which people are returned.
* The response is an array of people matching both the property criteria and the contact audience.
* Each person includes a `residence` object (where they live — not necessarily a property they own) and a nested `property` object (the associated property from the search).
* **Requested fields** (e.g., `estimated_value`) appear inside the nested `property` object.
* Billing includes people credits for returned people. Requested chargeable property fields add property credits.

***

## Notes

* At least one location, filter, list condition, or previous-export condition is required. An empty
  `filters` array is valid when another search criterion is present.
* All filters are combined with AND logic. See [Searching](/concepts/searching#filter-logic).
* `contact_audience` is **required** when `anchor` is `"people"` and defaults to `"owners"` when `anchor` is `"properties"`. Set to `"none"` to skip contacts entirely.
* When `anchor` is `"properties"`, people filters scope the `contacts` array but do not filter properties. A property with no matching contacts still appears with an empty `contacts` array.
* Billing follows the requested output. Property-anchored rows consume property credits, and returned
  contacts consume people credits. People-anchored rows consume people credits; property credits are
  added only when requested property output fields go beyond address/context. See [Credit-efficient
  queries](/concepts/credit-efficient-queries).
* Use `source_type=properties` and `source_type=people` when calling [List Filters](/api-reference/filters/list-filters) and [List Fields](/api-reference/fields/list-fields) to discover available filters and fields.

***

## Cost Estimate

Set `estimate_cost: true` to preview the credit cost of a search **before committing to it**. The request is validated identically to a real search — same filters, same pagination — but no data is returned and no credits are consumed.

```bash theme={null}
curl -X POST "https://api.v2.dealmachine.com/v1/properties/search" \
  -H "Authorization: Bearer dm_sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "estimate_cost": true,
    "locations": [
      { "type": "state", "code": "TX" }
    ],
    "anchor": "properties",
    "contact_audience": "owners",
    "filters": [
      { "filter_id": "estimated_value", "operator": "range", "value": { "min": 200000, "max": 600000 } }
    ],
    "page": 1,
    "per_page": 25
  }'
```

The response contains `totals`, `pagination`, and `estimated_credits` — but no `data` array:

```json theme={null}
{
  "totals": {
    "properties": 1847,
    "people": 2134
  },
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total_results": 1847,
    "total_pages": 74,
    "has_next_page": true,
    "has_previous_page": false
  },
  "estimated_credits": {
    "this_page": 25,
    "total_all_pages": 1847,
    "breakdown": {
      "properties": 25,
      "people": 0,
      "already_accessed": 0,
      "note": "Estimate based on requested output. Actual credits may be lower due to returned contact counts, active licenses, and deduplication within your billing period."
    }
  }
}
```

| Field                                          | Type    | Description                                                  |
| ---------------------------------------------- | ------- | ------------------------------------------------------------ |
| `estimated_credits.this_page`                  | integer | Estimated credits for this page before deduplication         |
| `estimated_credits.total_all_pages`            | integer | Credits all pages combined would consume                     |
| `estimated_credits.breakdown.properties`       | integer | Property data credits on this page                           |
| `estimated_credits.breakdown.people`           | integer | People data credits on this page when `anchor` is `"people"` |
| `estimated_credits.breakdown.already_accessed` | integer | Currently `0`; final usage applies billing-period dedup      |

<Tip>
  Cost estimate is free and does not consume credits. Use it as often as needed. To get just the
  total count without cost estimates, use [Count
  Properties](/api-reference/properties/count-properties).
</Tip>
