Query Parameters
List and search endpoints accept a common set of query parameters that let you filter, sort, paginate, and shape the payload returned by the API.
Parameter Reference
| Parameter | Type | Default | Limits | Applies to |
|---|---|---|---|---|
filter[field][op] |
map | — | Up to 10 filter fields per request | list, search |
sort |
string | The content type's default sort or -published_at |
100 characters | list, search |
page |
integer ≥ 1 |
1 |
— | list, search |
per_page |
integer | Content type setting, or 20 |
Max 100 |
list, search |
fields |
comma-separated string | All fields | 500 characters | list, search |
populate |
comma-separated string | No relations expanded | 500 characters | show |
q |
string | — | 2–200 characters | search |
fields and populate are strings, not arrays
Pass a single comma-separated string: ?fields=title,slug. The bracket-array syntax ?fields[]=title&fields[]=slug will not work.
Filters
Filters narrow a list or search response to entries that match the criteria you specify. They are applied using the filter[...] parameter, nested by field name.
Equality shorthand
For simple exact-match filters, you can omit the operator:
?filter[status]=published
?filter[category]=tech
Included in plan — when used alone
A single equality filter (eq) on a field marked filterable is the only filter served from the pre-computed cache, so it does not count against your plan. This holds only when the eq filter is used on its own. It escalates to a live (metered) query the moment you:
- add a
sort, or - combine it with a second filter.
See Request Metering.
Operator syntax
For anything other than equality, nest the operator inside a second bracket:
?filter[status][eq]=published
?filter[views][gte]=100
?filter[title][contains]=laravel
?filter[category][in]=tech,news
Supported operators
| Operator | Meaning | Example | Notes |
|---|---|---|---|
eq |
Equals | filter[status][eq]=published |
The default when no operator is given |
neq |
Not equal | filter[status][neq]=archived |
|
gt |
Greater than | filter[views][gt]=100 |
Numeric comparison |
gte |
Greater than or equal | filter[views][gte]=100 |
Numeric comparison |
lt |
Less than | filter[price][lt]=50 |
Numeric comparison |
lte |
Less than or equal | filter[price][lte]=50 |
Numeric comparison |
contains |
Case-insensitive substring (ILIKE) | filter[title][contains]=laravel |
% and _ in the input are escaped |
starts_with |
Prefix match (ILIKE) | filter[title][starts_with]=How |
Case-insensitive |
in |
Value in a comma-separated list | filter[category][in]=tech,fashion |
|
nin |
Value not in the list | filter[category][nin]=tech |
Do not use like — it is silently ignored
For a case-insensitive substring match, always use contains. While the underlying query engine recognises like, the edge router that serves CMS requests does not: a filter[field][like]=… request is not detected as a filter at all. Instead of an error, the API quietly returns the unfiltered list as if no filter had been applied. contains performs the exact same ILIKE substring match and is routed correctly, so prefer it in all cases.
Combining filters
You can combine multiple filter fields in a single request. All conditions are applied with AND:
?filter[category]=tech&filter[views][gte]=100&filter[status]=published
Combined filters are metered
The pre-computed cache stores results for single equality filters only. Any time you combine two or more filters in one request, the API falls back to a live query and the request counts against your plan.
Rules & validation
- A filter field must appear in the content type's
filterable_fieldslist (available from the schema endpoint). Filtering on any other field returns400 INVALID_FILTER. - Filter operators must be one of the values above. Unknown operators return
400 INVALID_OPERATOR. The one exception islike: it is not rejected with an error — it is silently ignored and the unfiltered list is returned (see the warning above). Usecontainsinstead. - You may include up to 10 filter fields in a single request. Beyond that, the API returns
400 TOO_MANY_FILTERS.
Sort
Use the sort parameter with a single field name. Prefix with - for descending order.
?sort=title # Ascending by title
?sort=-title # Descending by title
?sort=-published_at # Descending by publish date
| Rule | Behaviour |
|---|---|
Timestamp fields (published_at, created_at, updated_at) default to descending if no - prefix is given. |
sort=published_at → newest first. |
| Other fields default to ascending. | sort=title → A → Z. |
The field must appear in the content type's sortable_fields or be a timestamp column. |
Otherwise returns 400 INVALID_SORT. |
Single-field sorts are included in plan
Sorts on fields that have been enabled for sorting are pre-computed. Combining sort with filter or any other query parameter shifts the request to dynamic (metered) mode.
Pagination
Pagination is 1-based. Requests without a page parameter return page 1.
?page=2&per_page=20
| Parameter | Default | Max |
|---|---|---|
page |
1 |
— |
per_page |
Content type setting, or 20 otherwise |
100 |
The response envelope always includes a meta block with pagination metadata — see Responses.
Sparse Fieldsets
By default the API returns every field defined on the content type. If you only need a subset (for list views, previews, etc.), request them with fields:
?fields=title,slug,published_at
- Pass a comma-separated list — no brackets.
- Unknown fields are silently dropped.
- The
idfield is always returned, regardless of whether you include it. - If you request a
mediafield, the generated{field}_urlcompanion is also included automatically.
Example
GET /api/v1/blog_posts?fields=title,slug,featured_image&per_page=5 HTTP/1.1
Host: cms.appambit.com
X-App-Key: {YOUR_APP_KEY}
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "10 Laravel Tips",
"slug": "10-laravel-tips",
"featured_image": "b3c1f2.jpg",
"featured_image_url": "https://cms.appambit.com/{YOUR_APP_KEY}/cms/media/b3c1f2.jpg"
}
],
"meta": { "current_page": 1, "per_page": 5, "total": 42, "last_page": 9 }
}
Relation Population (populate)
On the single-entry endpoint you can ask the API to embed the full data of related entries instead of returning only their UUIDs. See Relations for the full response shape.
?populate=author_id
?populate=author_id,category_id
Constraints
- One level deep — you cannot populate relations of the populated entries.
- Only the single-entry
showendpoint supportspopulate. It is not available on list or search endpoints. - Related entries must themselves be published; unpublished ones are omitted.
Populate is always metered
The plain entry response is pre-computed and free. Adding ?populate=... forces a live query, so the request counts against your plan.