Skip to content

Search Products

The list endpoint at GET /api/shop/products doubles as the search & filter endpoint. Every storefront facet — keyword search, category, price range, attribute filters, sort, "new" / "featured" — is just a query parameter. This page is the complete reference for those parameters.

The GraphQL products field expresses the same filters differently — a JSON filter: string, sortKey / reverse, and cursor pagination instead of query parameters. See List Products on the GraphQL side.

Endpoint

GET /api/shop/products

Same URL as Products; the only difference is which query parameters you send.

Reserved parameters

These names are interpreted by the search/sort/pagination layer — never as attribute filters:

ParameterTypeDefaultDescription
querystringSearch term. Matches against product SKU and product name.
sortstringSort token. Either compound (name-asc, price-desc) or a bare key paired with order (sort=name&order=desc). See Sort tokens below.
orderstringascDirection when sort is a bare key. Ignored if sort already has a -asc / -desc suffix.
pageinteger11-based page number.
per_pageinteger30Items per page. Max 50.
localestringLocale override (alternative to the X-Locale header).
channelstringChannel override (alternative to the X-Channel header).
filterstringJSON filter object — GraphQL parity. Example: {"color":{"match":"3","match_type":"PARTIAL"}}. Most clients prefer the simpler ?<attribute>=<id> shorthand.
typestringProduct type. One of simple, configurable, bundle, grouped, virtual, downloadable, booking.
category_idintegerFilter by category ID. categoryId (camelCase) is also accepted.
pricestringCompound price range in the exact form {min},{max} — the comma separates minimum from maximum, it is not a thousands separator. ?price=10,200 means min 10, max 200. Use . for decimals and no grouping (e.g. ?price=1000,5000.50), never ?price=1,000.
price_fromnumberMinimum price (inclusive). Same as the {min} in price.
price_tonumberMaximum price (inclusive). Same as the {max} in price.
newboolean1 to restrict to products with the "new" flag set.
featuredboolean1 to restrict to products with the "featured" flag set.

Attribute filters (anything else)

Any query parameter not listed above is treated as a filterable attribute code. Nothing needs changing when a merchant adds a new filterable attribute — the parameter works as soon as the attribute exists.

PatternExampleEffect
?<code>=<option_id>?color=3Single option ID match
?<code>=id1,id2,…?size=4,5,6Multi-option (OR) match
?brand=N, ?material=N?material=12Same shape — works for any filterable attribute
?filter[color]=3&filter[size]=5(Swagger UI form)API Platform's bracket-syntax form. Same semantics as the bare-key form.

To list which attributes are filterable and what their option IDs are, fetch GET /api/shop/attributes and look for isFilterable: 1. Each attribute's options[] array has the IDs.

Sort tokens

The compound form (<key>-<dir>) is recommended:

TokenSort by
name-ascProduct name, A→Z
name-descProduct name, Z→A
price-ascPrice, low→high
price-descPrice, high→low
created_at-ascOldest first
created_at-descNewest first
updated_at-ascOldest update first
updated_at-descMost recently updated first
id-ascAscending ID (catalog order)
id-descDescending ID

Alternative form: ?sort=name&order=desc. Pick one; mixing them isn't useful.

Combining filters

All filters are AND-combined. There is no OR across different filters — the only multi-value form is comma-separated values within a single attribute (?size=4,5,6).

GET /api/shop/products?
  category_id=5
  &color=3
  &size=4,5
  &price=10,200
  &new=1
  &sort=price-desc
  &per_page=24

Response

200 OK — JSON array of card-level product objects (same shape as Products). Pagination headers always emitted.

A filter that matches nothing returns an empty array with 200 OK and X-Total-Count: 0. It does not 404.

Common pitfalls

  • Sending itemsPerPage instead of per_page — the legacy API Platform name is not accepted.
  • Filtering by an attribute that isn't flagged isFilterable=1 — the parameter is silently ignored.
  • Filtering by an attribute code but passing an option label (e.g. ?color=Red) — values are matched against option IDs, not labels.
  • Reading the comma in price as a thousands separator — it isn't. ?price=10,200 is min 10 / max 200, not "10200". Never group digits (?price=1,000 is invalid); write ?price=1000,5000.
  • Combining price + price_from/price_to — pick one. The compound form wins if both are present.
  • Assuming an unknown sort token errors — it does not. ?sort=bogus-desc answers 200 with the default catalog order, so a typo looks like "sorting is broken" rather than a rejected request.
  • Products — same endpoint with no filters
  • Single Product — fetch one product after the user picks a result
  • Categories — discover category IDs for ?category_id=N
  • Attributes — discover filterable attribute codes
  • Pagination — the page, per_page, and header conventions used here

Released under the MIT License.