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

# Sorting and filtering

> The query parameter conventions collection endpoints use for sorting and filtering: syntax, operators, and how parameters combine.

Collection endpoints like `/calls`, `/contacts`, and `/conversations` share one convention for sorting and filtering. Learn it once and it applies everywhere it's supported — check each endpoint's reference page for which fields are sortable or filterable.

## Sorting

Endpoints that support sorting accept a single `sort` query parameter: a comma-separated list of `field:direction` pairs.

```plain theme={null}
GET /calls?sort=createdAt:desc
GET /contacts?sort=lastName:asc,firstName:asc
GET /conversations?sort=lastActivityAt:desc,phoneNumber:asc
```

Direction is `asc` or `desc`. A pair with a missing or unrecognized direction is rejected with a [`400`](/docs/2026-03-30/errors#status-codes).

When you provide multiple pairs, they apply left-to-right — each field after the first breaks ties in the one before it. `sort=lastActivityAt:desc,phoneNumber:asc` above sorts conversations by most recent activity, using phone number ascending only to break ties among conversations with the same activity time.

`field` supports dot notation for nested or relationship fields, and direction pairing works the same way:

```plain theme={null}
GET /contacts?sort=workspace.name:asc
```

## Filtering

Endpoints that support filtering expose one query parameter per filterable field. Equality is the implicit default, and every parameter present in the query string combines with logical AND — there's no implicit OR across distinct parameters.

```plain theme={null}
GET /calls?status=missed
GET /calls?status=missed&direction=inbound
GET /contacts?workspaceId=42&tag=lead
```

Parameter names use the singular field name, even for filters that accept multiple values (`source`, not `sources`).

### Operators

Non-equality operators are appended to the field name in brackets:

| Syntax            | Operator                                     |
| ----------------- | -------------------------------------------- |
| `field[gt]`       | greater than                                 |
| `field[gte]`      | greater than or equal                        |
| `field[lt]`       | less than                                    |
| `field[lte]`      | less than or equal                           |
| `field[ne]`       | not equal                                    |
| `field[in]`       | one of a comma-separated set                 |
| `field[all]`      | all of a comma-separated set must be present |
| `field[contains]` | substring match (text fields only)           |

```plain theme={null}
GET /calls?duration[gte]=300&createdAt[gte]=2026-07-29T00:00:00Z
GET /contacts?workspaceId[in]=42,88,101&status[ne]=archived
```

### OR logic

Values within a single `[in]` parameter OR together — `status[in]=missed,voicemail` matches either status. That's the only place OR applies: parameters across the query string still AND, so `status[in]=missed,voicemail&direction=inbound` requires the inbound direction on top of either status.

Cross-field OR (for example, "status is missed OR duration over 600") isn't supported. There's no bracket or suffix in this scheme that expresses OR across distinct fields, so don't try to construct one — build the request as two separate calls instead, or get in touch if this is a hard blocker for your use case.
