> For the complete documentation index, see [llms.txt](https://api-docs.visadoc.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api-docs.visadoc.co/filters.md).

# Filters

Every `search` endpoint accepts a `filters` object so you fetch exactly the rows you need instead of pulling everything and filtering client-side. Filtering works against **any field the endpoint returns**: if a key appears in that endpoint's output, you can filter on it.

## Shape

```json
{
  "page": 1,
  "per_page": 25,
  "filters": {
    "destination": "AUS",
    "status": ["Documents", "Application Form"],
    "price": { "gte": 100, "lte": 500 },
    "created_at": { "gte": 1737331200000 }
  }
}
```

## How the operators read

| Form         | Meaning                                       | Example                               |
| ------------ | --------------------------------------------- | ------------------------------------- |
| Scalar       | Exact match                                   | `"destination": "AUS"`                |
| Array        | Any of these values (OR **within one field**) | `"status": ["Documents", "Profile"]`  |
| Range object | Bounded range                                 | `"price": { "gte": 100, "lte": 500 }` |

Arrays work for IDs too, so you can fetch many records in one call instead of one call per ID.

## Use the output field names

The filter key is the field name **as it appears in that endpoint's response**, which isn't always the name used elsewhere. The common case: on `applications/search` the assessment is in the field `assessment`, so filter on `assessment`, not `assessment_id`.

```json
{
  "page": 1,
  "per_page": 25,
  "filters": {
    "assessment": [
      "fb5a2866-a834-4547-b24d-14cbdc111111",
      "95e2368c-633a-4d66-b013-e0f26b111111"
    ]
  }
}
```

## Business examples

* Applications created from your assessments → `{ "filters": { "assessment": ["…", "…"] } }` on `applications/search`.
* Every case waiting on documents → `{ "filters": { "status": ["Documents"] } }` on `applications/search`.
* One case's documents → `{ "filters": { "application_id": "…" } }` on `documents/search`.
* Documents that failed a check → `{ "filters": { "status": "Error" } }` on `documents/search`.
* One case's audit history → `{ "filters": { "application_id": "…" } }` on `actions/search`.
* Everything that changed since your last sync → `{ "filters": { "created_at": { "gte": 1737331200000 } } }` on `actions/search`.
* Australia cases only → `{ "filters": { "destination": "AUS" } }` on `applications/search`.

## Best practices

* **Filter keys must be real output fields.** A key that isn't in that endpoint's response matches nothing, silently, and you get an empty result rather than an error.
* **Timestamps are epoch milliseconds, not dates.** Use `{ "created_at": { "gte": 1737331200000 } }`, never `"2026-01-20"`.
* **Batch IDs into arrays.** One call with a list of IDs beats one call per ID.
* **Narrow on the server.** Combining filters returns less data and is faster than fetching all rows and filtering locally.
* **Always page.** Set `page` (starting at `1`) and `per_page`. On `applications/search` and `documents/search`, follow `nextPage` until it is `null`; on `applicants/search` and `actions/search` (plain arrays), request the next page until you get fewer items than `per_page`.
