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

# Pagination & Sorting

> How to paginate and sort search results

Search endpoints return paginated results. You control the page size, navigate through pages, and optionally sort by one or more fields.

## Pagination Parameters

Include these in your search request body:

```json theme={null}
{
  "page": 1,
  "per_page": 25
}
```

| Parameter  | Type    | Default | Min | Max   | Description                 |
| ---------- | ------- | ------- | --- | ----- | --------------------------- |
| `page`     | integer | `1`     | `1` | —     | The page number to retrieve |
| `per_page` | integer | `25`    | `1` | `250` | Number of results per page  |

Both parameters are optional. If omitted, the defaults apply.

## Pagination Response

Every search response includes a `pagination` object alongside the `data` array:

```json theme={null}
{
  "data": [ ... ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total_results": 1847,
    "total_pages": 74,
    "has_next_page": true,
    "has_previous_page": false
  }
}
```

| Field               | Type    | Description                                   |
| ------------------- | ------- | --------------------------------------------- |
| `page`              | integer | Current page number                           |
| `per_page`          | integer | Results per page (as requested)               |
| `total_results`     | integer | Total number of matching records              |
| `total_pages`       | integer | Total number of pages                         |
| `has_next_page`     | boolean | `true` if there are more pages after this one |
| `has_previous_page` | boolean | `true` if there are pages before this one     |

## Sorting

Sort results by one or more fields using the `sort` array:

```json theme={null}
{
  "sort": [
    { "field_id": "estimated_value", "direction": "desc" }
  ]
}
```

| Key         | Type   | Required | Description                                  |
| ----------- | ------ | -------- | -------------------------------------------- |
| `field_id`  | string | Yes      | The field to sort by                         |
| `direction` | string | Yes      | `"asc"` (ascending) or `"desc"` (descending) |

### Multi-column sorting

Pass multiple sort objects to sort by multiple fields. They are applied in order — the first entry is the primary sort, the second breaks ties, and so on.

```json theme={null}
{
  "sort": [
    { "field_id": "state", "direction": "asc" },
    { "field_id": "estimated_value", "direction": "desc" }
  ]
}
```

This sorts by state alphabetically, then by estimated value (highest first) within each state.

### Default sort

If you omit the `sort` parameter, the server applies a default sort order. The default varies by endpoint but generally returns the most relevant results first.

### Sortable fields

Not all fields support sorting. Use the [List Fields](/api-reference/fields/list-fields) endpoint to check which fields are available, then refer to the endpoint documentation for sorting constraints.

Attempting to sort by a non-sortable field returns a `validation_error`.

## Iterating Through All Pages

To retrieve all results, loop through pages until `has_next_page` is `false`.

<CodeGroup>
  ```bash cURL theme={null}
  # Page 1
  curl -X POST "https://api.v2.dealmachine.com/v1/properties/search" \
    -H "Authorization: Bearer dm_sk_live_xxx" \
    -H "Content-Type: application/json" \
    -d '{
      "filters": [...],
      "page": 1,
      "per_page": 250
    }'

  # Page 2
  curl -X POST "https://api.v2.dealmachine.com/v1/properties/search" \
    -H "Authorization: Bearer dm_sk_live_xxx" \
    -H "Content-Type: application/json" \
    -d '{
      "filters": [...],
      "page": 2,
      "per_page": 250
    }'
  ```

  ```javascript Node.js theme={null}
  const API_KEY = "dm_sk_live_xxx";
  const BASE_URL = "https://api.v2.dealmachine.com/v1/properties/search";

  async function fetchAllProperties(filters) {
    const allResults = [];
    let page = 1;
    let hasNextPage = true;

    while (hasNextPage) {
      const response = await fetch(BASE_URL, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          filters,
          page,
          per_page: 250,
        }),
      });

      const { data, pagination } = await response.json();
      allResults.push(...data);

      hasNextPage = pagination.has_next_page;
      page++;
    }

    return allResults;
  }
  ```

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

  API_KEY = "dm_sk_live_xxx"
  BASE_URL = "https://api.v2.dealmachine.com/v1/properties/search"

  def fetch_all_properties(filters):
      all_results = []
      page = 1

      while True:
          response = requests.post(
              BASE_URL,
              headers={"Authorization": f"Bearer {API_KEY}"},
              json={
                  "filters": filters,
                  "page": page,
                  "per_page": 250,
              },
          )
          body = response.json()
          all_results.extend(body["data"])

          if not body["pagination"]["has_next_page"]:
              break
          page += 1

      return all_results
  ```
</CodeGroup>

## Performance Tips

<CardGroup cols={2}>
  <Card title="Use smaller pages for faster responses">
    Smaller `per_page` values return faster. Use `per_page: 25` for interactive UIs and `per_page: 250` for batch processing.
  </Card>

  <Card title="Only fetch what you need">
    Use the `fields` parameter to request only the fields you need. Fewer fields means smaller payloads and faster responses.
  </Card>

  <Card title="Avoid deep pagination">
    Requesting very high page numbers (e.g., page 500) is slower than early pages. If you need to process large result sets, consider narrowing your filters instead.
  </Card>

  <Card title="Sort deliberately">
    Sorting by indexed fields is faster. If performance matters, avoid multi-column sorts on non-indexed fields.
  </Card>
</CardGroup>
