Categories
The endpoint always filters to status = 1, so a category a merchant has disabled is never returned and its ID responds 404.
This is a flat list. For the nested menu structure use Get Category Tree.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/categories | Flat, paginated list of active categories |
| GET | /api/shop/categories/{id} | Single category by ID |
Use the example switcher above the curl block to flip between the two.
Request Headers
| Header | Required | Description |
|---|---|---|
Accept | Yes | application/json |
X-STOREFRONT-KEY | Yes | Storefront API key (pk_storefront_…) |
X-Locale | No | Override request locale |
X-Channel | No | Override channel scope |
Query Parameters (collection only)
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-based) |
per_page | integer | 15 | Items per page. Max 100 for this endpoint. |
parent_id | integer | — | Return only direct children of this category ID. Accepts parentId as alias. |
Pagination headers (X-Total-Count, X-Page, X-Per-Page, X-Total-Pages) are emitted on the collection. See Pagination.
Category Object Fields
Both endpoints return the same shape — the collection is an array of these objects, the single endpoint returns one.
| Field | Type | Description |
|---|---|---|
id | integer | Category primary key. |
position | integer | Display order. |
status | boolean (0/1) | Always 1 here — the storefront endpoints never return disabled categories. |
displayMode | string | products_and_description, products, or description_only. |
logoPath | string | Storage path of the category image. Absent when no image is set, rather than null. |
logoUrl | string | Fully-qualified image URL. Absent alongside logoPath. |
url | string | Storefront URL of the category page. |
minPrice / maxPrice | number | Cheapest and dearest product price in the category, for a price-range filter. Both are 0 when the category holds no priced products. |
_lft / _rgt | integer | Nested-set tree pointers — internal bookkeeping, safe to ignore. |
createdAt / updatedAt | string | ISO 8601 timestamps. |
translation | object | Translation for the request locale, inline — see below. |
translations | array | Path references to every stored translation, e.g. /api/shop/category_translations/1. |
parent | string | Path of the parent category. Absent on a root category. |
children | array | Path references to the direct children, e.g. /api/shop/categories/5. Empty for a leaf. |
filterableAttributes | array | Attributes flagged filterable for this category, inline. Empty when none are configured. |
Two things differ from what a client might assume: children and translations are path references, not inline objects, so building a tree from this endpoint costs one request per level — use Get Category Tree instead. And null-valued fields are omitted entirely rather than returned as null, so a client must test for key presence, not for a null value.
Inline Translation Fields
| Field | Type | Description |
|---|---|---|
id | integer | Translation primary key |
categoryId | integer | Owning category ID |
locale | string | Locale code (en, fr, de, …) |
name | string | Localized category name |
slug | string | URL slug (e.g. electronics) |
urlPath | string | Full URL path including any parent slugs |
description | string | HTML description shown on the category page |
metaTitle | string | SEO <title> value |
metaDescription | string | SEO meta description |
metaKeywords | string | SEO meta keywords |
See IRIs & HATEOAS for how to dereference the IRI fields.
Category Attribute Filters
Each category inlines the facets its product listing can be narrowed by, under filterableAttributes, plus minPrice and maxPrice for a price slider. There is no separate filters endpoint — reading the category is enough to build the whole facet sidebar.
Only attributes an admin flagged filterable appear here, so the array is already the correct facet set for that category. It is empty when none are configured.
Filter Fields
Each entry is a full attribute record. The ones a facet UI actually needs:
| Field | Description |
|---|---|
code | The query-parameter name to send to the product listing, e.g. color. |
type | select, multiselect, price, boolean, and so on — decides whether you render checkboxes, a slider, or a toggle. |
adminName | Back-office label. Show translation.name to shoppers instead. |
translation | The label for the request locale, as { name }. translations lists the rest as path references. |
position | The order the store configured; sort the sidebar by it. |
options | Selectable values, empty for price and other non-option types. |
isConfigurable | Whether variants are also built from this attribute — useful when a filter doubles as a variant selector. |
Option Fields
| Field | Description |
|---|---|
id | The value to send when filtering. Filters match option ids, never labels. |
adminName | Back-office label for the option. |
translation | The shopper-facing label for the request locale, as { label }. |
sortOrder | Display order within the facet. |
Applying the Filters
Take the attribute's code as the parameter name and the option's id as the value, then send them to the product listing:
GET /api/shop/products?category_id=2&color=1&size=4,5&price=24.99,299.99- Comma-separate ids inside one attribute for an OR match —
?size=4,5means size 4 or 5. - Separate parameters are AND-combined — the example asks for red products that are size 4 or 5.
pricetakes theminPrice,maxPricepair from the category as its bounds; the comma separates the two numbers and is never a thousands mark.- Sending an option label rather than its id matches nothing and returns an empty list, not an error.
Full parameter reference is on Search Products.
Use Cases
- Sidebar or footer category list — the flat collection is one call, and each row already carries
urland the localisednameinsidetranslation. - Subcategory widget —
?parent_id=Nreturns the direct children as full objects, which thechildrenpath references alone would not give you. - Category-page facets —
filterableAttributesis inline, so a faceted filter needs no second request;minPriceandmaxPricebound a price slider. - Breadcrumbs — follow
parentupwards; its absence marks the root.
Best Practices
- Test for key presence, not for
null—logoPath,logoUrl, andparentare dropped from the payload when empty. - Do not build a tree from
children— they are references; Get Category Tree returns the nested structure in one call. - Read names from
translation, not the top level — the category object itself carries noname; it lives in the locale block. - Send
X-Localerather than dereferencingtranslations— the inlinetranslationalready follows the request locale.
Related Resources
- Get Category Tree — hierarchical tree response
- Get Products — pass
?category_id=Nto filter by category - Introduction → IRIs & HATEOAS — how to dereference the path references in these payloads

