Skip to content

Filtering

Filtering is a common requirement for collection endpoints in APIs. When listing resources (for example, GET /books), clients often need to narrow results to only those that match specific criteria such as state, owner, category, or timestamps.

Filtering applies deterministic, field-aware constraints that are index-friendly and predictable. Filtering is distinct from:

  • Sorting (ordering results)
  • Pagination (windowing results)
  • Searching (partial text matching, fuzzy queries, complex boolean logic)

APIs may support filtering on collection endpoints. If supported:

  • Filtering must be modeled as explicit query parameters on a GET request (not request body). It must not be modeled as a single filter string with a custom language/grammar. Query parameters must follow the naming and encoding rules in AEP-106.
  • Filtering parameters must not change the meaning of the resource model; they only constrain which items appear in the collection response.
  • APIs must document:
    • Supported filter parameters
    • Accepted value formats (especially timestamps)
    • Case sensitivity rules for string matching

Examples:

### Get all books published after 2025-01-01
GET /books?publishedTimeAfter=2025-01-01T00:00:00Z
### Get all published books
GET /books?state=published

Different APIs have different resource models and user needs, so the set of filterable fields and supported operators will vary. These guidelines ensure consistency in how filters are named and composed, while allowing each API to decide which filters to offer based on real use cases. Just because an operator is listed here doesn’t mean it needs to be implemented. Instead, this is saying “if you need to implement this parameter, name it this”.

Filtering parameter names must be stable (do not rename lightly), specific, and self-explanatory.

APIs must use the direct field name for exact matches (e.g. state=active, category=books).

APIs should use the following prefix/suffix modifiers for common comparisons. Use consistent prefixes/suffixes and only introduce them when there is more than one plausible comparison. APIs should use a subset as appropriate.

Filtering operationPatternExample
Equals{field}status=ACTIVE
Not equals{field}NotEqualstatusNotEqual=CANCELLED
Lower bound
(exclusive) >
{field}GreaterThanpriceGreaterThan=100
Upper bound
(exclusive) <
{field}LessThanpriceLessThan=100
Lower bound
(inclusive)
{field}GreaterThanOrEqual
min{Field}
minimum{Field}
priceGreaterThanOrEqual=100
minCapacity=50
minimumCapacity=50
Upper bound
(inclusive)
{field}LessThanOrEqual
max{Field}
maximum{Field}
priceLessThanOrEqual=100
maxCapacity=500
maximumCapacity=500
Timestamp lower
bound (exclusive) >
{field}AfterpublishedTimeAfter=2025-01-01
Timestamp upper
bound (exclusive) <
{field}BeforepublishedTimeBefore=2025-01-01
Timestamp lower
bound (inclusive)
earliest{Field}earliestPublishedTime=2025-01-01
Timestamp upper
bound (inclusive)
latest{Field}latestPublishedTime=2025-01-01
Nullability and existencehas{Field}hasPhoneNumber=true

When multiple different filter parameters are provided, the API must combine them using logical AND.

Example:

### products that are in the "books" category AND active
GET /products?category=books&state=active

When the same filter parameter appears multiple times, or has a comma-separated list, the API should interpret it as an OR for that field, and combine it with other filter parameters using AND ( see Combining filters).

See Repeated and list query parameters for more details on repeated parameters and comma-separated lists.

Modeling a general OR across different fields (e.g., category=books OR state=active) is difficult to represent cleanly in query parameters and often leads to ad-hoc mini-languages.

Therefore, APIs should not support arbitrary boolean logic across different fields in query strings. If a real use case requires it, APIs should implement a specialized search endpoint.

Query parameters do not naturally express “field is missing” vs. “field is present but empty”. APIs should avoid exposing “missing vs present” semantics unless necessary. If existence filtering is required, APIs may add explicit parameters such as has{field}=true|false

Example:

GET /users?hasPhoneNumber=true

APIs must document exactly what “has” means for each field (non-null, non-empty string, non-empty array, etc.). The semantics must be consistent within a single API.

APIs should treat unknown filter parameters as a client mistake, returning a 400 Bad Request with a clear message indicating the unsupported parameter(s).

APIs must validate filter values and return 400 Bad Request for invalid formats (e.g., invalid timestamp).

If the API intentionally ignores unknown parameters for backwards/forwards compatibility, that behavior must be documented (but this is discouraged for filtering because silent failure is hard to detect).

APIs should support filtering only for deterministic, field-aware constraints that are index-friendly and predictable. APIs must not introduce relevance ranking, fuzziness, or cross-field query logic under “filtering”. If requirements exceed deterministic filtering, APIs should use (a) dedicated search endpoint(s).

Filtering is designed for precise, deterministic matching (e.g., “state is ACTIVE” or “price greater than 100”). APIs * *must** support filtering only for deterministic, field-aware constraints that are index-friendly and predictable. APIs **must not** introduce partial text matching, wildcards, relevance ranking, fuzziness, or cross-field query logic under “filtering”. These operations belong in dedicated search endpoints.

For example, these are NOT filtering: name=Victor* (wildcard), description=~fuzzy match~ (fuzzy search).

If requirements exceed deterministic filtering, APIs must use dedicated search endpoint(s).

Filtering can create expensive queries. APIs must:

  • Document which fields are filterable.
  • Set limits (maximum number of filter values, maximum string length, etc.) as needed.
  • Ensure that adding filters does not allow clients to bypass authorization rules (filters constrain after access control, not instead of it).

Multi-parameter filtering using explicit query parameters is the most interoperable and REST-aligned approach. It is simple, cache-friendly, naturally integrates with OpenAPI documentation and SDK generation, and leverages standard query parameter parsing built into every web framework. This approach avoids single-parameter filter DSLs, which historically struggle with cross-language consistency, require custom parsers, and often result in partial implementations that defeat standardization benefits. For an in-depth analysis of filtering strategies and the decision process behind these guidelines, see ADR-001: REST API Filtering and Searching Strategy.

  • 2026-03-06: Move guidance on repeated parameters to AEP-106.
  • 2026-02-18: Change format from underscore (_) to camelCase. Add to naming conventions table. Use full words instead of abbreviations.
  • 2026-01-27: Removed search guidance, it will be a separate AEP. Align guidance with ADR-001.
  • 2025-12-11: Initial creation, adapted from Google AIP-160 and aep.dev AEP-160.