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
querystring—Search term. Matches against product SKU and product name.
sortstring—Sort 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.
localestring—Locale override (alternative to the X-Locale header).
channelstring—Channel override (alternative to the X-Channel header).
filterstring—JSON filter object — GraphQL parity. Example: {"color":{"match":"3","match_type":"PARTIAL"}}. Most clients prefer the simpler ?<attribute>=<id> shorthand.
typestring—Product type. One of simple, configurable, bundle, grouped, virtual, downloadable, booking.
category_idinteger—Filter by category ID. categoryId (camelCase) is also accepted.
pricestring—Compound 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_fromnumber—Minimum price (inclusive). Same as the {min} in price.
price_tonumber—Maximum price (inclusive). Same as the {max} in price.
newboolean—1 to restrict to products with the "new" flag set.
featuredboolean—1 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.