Skip to content

Products

The Products menu is the catalog's product-management surface — list, search, create, edit, copy, and delete products, plus manage each product's images, per-source inventory, and customer-group prices. It mirrors the admin Catalog → Products screen.

Product types

Every product has a type, fixed at creation. There are seven:

TypeNotes
simpleA standalone product with its own price and stock.
virtualLike simple but non-shippable (no weight/dimensions) — services, memberships.
downloadableSells downloadable links (paid files) and samples (free previews); non-stockable.
groupedA storefront grouping of other simple products (linked products); has no own price.
bundleA configurable kit built from bundle options; its price is calculated from the chosen items.
configurableA parent with variants generated from variant-defining attributes (super_attributes, e.g. colour × size). Each variant is its own SKU with its own price/stock.
bookingA bookable product (default / appointment / event / rental / table sub-types) with time slots; non-stockable.

Composite types own no price or stock of their own. For configurable, bundle, grouped, and booking, the price and inventory live on the children — the variants, bundle items, linked products, or slots. Their top-level price / quantity are derived or empty.

Creating a product is two steps

Creation is deliberately minimal: a POST creates the shell from just sku + attribute_family_id + type (plus super_attributes for configurable). Everything else — name, description, price, images, categories, channels, inventory — is filled in afterwards via the update endpoint. This mirrors the admin's create-then-edit wizard.

status vs visibleIndividually

Two independent flags control storefront presence:

  • status1 enabled / 0 disabled. A disabled product is fully hidden from the storefront.
  • visibleIndividually — whether the product appears in category/search listings. Variant products and grouped-component products are usually set to 0 (reachable only through their parent), while still being status = 1.

Both must effectively be on for a product to be browsable on its own. (status is stored on the flattened product table, resolved per channel + locale.)

Per-product sub-resources

The product edit screen's tabs map to their own endpoint groups, each scoped to one product:

  • Images — upload, reorder, and delete a product's images.
  • Inventories — read and bulk-update the per-inventory-source stock quantities.
  • Customer-group prices — tiered prices that apply to specific customer groups.

These are not returned in full on the listing (they're detail-only); the single-product endpoint embeds them inline.

The product listing

GET /api/admin/catalog/products is the datagrid — a paginated { data, meta } envelope.

Listing filters (AND-combined)

All filters are combined with AND — every filter you add narrows the result set further. Pass them as query parameters:

FilterTypeDescription
channelstringChannel code used to resolve per-channel values.
namestringPartial product-name match.
skustringPartial SKU match.
attribute_familyintegerAttribute-family ID.
price_from / price_tonumberPrice band (inclusive). price=50,200 is shorthand for price_from=50&price_to=200.
product_idstringA single ID, or a comma-separated list (e.g. 1,22,2705).
statusinteger0 (disabled) or 1 (active).
typestringOne of the seven product types.
localestringLocale code used to resolve translated values.

Plus pagination and sort:

ParameterTypeDescription
pageinteger1-based page number (default 1).
per_pageintegerPage size (default 10, max 50).
sortstringproduct_id (default), sku, name, type, status, price, quantity, attribute_family, channel.
orderstringasc or desc (default desc).

Listing columns

Every row carries these scalar columns. Heavy fields are null on the listing (fetch them from the detail endpoint):

FieldTypeNotes
idintegerProduct ID.
skustringSKU.
namestring|nullResolved for the active locale/channel. null for draft products with no name yet.
typestringProduct type.
statusinteger1 active / 0 disabled.
pricestring|nullBase price (composite types carry no own price → null).
formattedPricestring|nullLocale-formatted base price.
specialPricestring|nullDiscounted price, when a special price is set.
formattedSpecialPricestring|nullLocale-formatted special price.
specialPriceFromstring|nullStart date of the special-price window (null = always on).
specialPriceTostring|nullEnd date of the special-price window (null = no end).
quantityintegerTotal stock across inventory sources.
baseImageUrlstring|nullMedium-cache base image URL.
imagesCountintegerNumber of images.
categoryIdinteger|nullPrimary category ID.
categoryNamestring|nullPrimary category name.
channelstringResolved channel code.
localestringResolved locale code.
attributeFamilyIdintegerAttribute-family ID.
attributeFamilyNamestringAttribute-family name.
urlKeystring|nullStorefront URL slug.
visibleIndividuallybooleanAppears in category/search listings.
shortDescription / descriptionstring|nullResolved content.
metaTitle / metaDescription / metaKeywordsstring|nullSEO fields.
weightnumber|nullProduct weight.
featuredbooleanFeatured flag.
newboolean"New" flag.
createdAt / updatedAtstringTimestamps.
taxCategoryIdinteger|nullDetail-onlynull on the listing.
manageStockboolean|nullDetail-onlynull on the listing.
inStockboolean|nullDetail-onlynull on the listing.
translations, images, categories, inventories, customerGroupPrices, superAttributes, variants, bundleOptions, linkedProducts, downloadableLinks, downloadableSamplesarray|nullRelation blocks — all null on the listing; populated only on the detail endpoint.

Actions

ActionWhat it does
CopyDuplicates an existing product into a new draft product (a fresh SKU is generated).
Mass deleteDeletes several products at once — body { "indices": [1, 22] }. Missing IDs are skipped.
Mass update statusBulk enable/disable — body { "indices": [1, 22], "value": 0 } (0 = disable, 1 = active).
Export (CSV)Downloads the listing as a CSV file, honouring the current filters; exports every matching row, not just the page. REST only.

Endpoints in this menu

ActionEndpoint
List productsGET /api/admin/catalog/products
Product detailGET /api/admin/catalog/products/{id}
Create productPOST /api/admin/catalog/products
Update productPUT /api/admin/catalog/products/{id}
Delete productDELETE /api/admin/catalog/products/{id}
Copy productPOST /api/admin/catalog/products/{id}/copy
Mass deletePOST /api/admin/catalog/products/mass-delete
Mass update statusPOST /api/admin/catalog/products/mass-update-status
Export products (CSV)GET /api/admin/catalog/products/export
Upload imagesPOST /api/admin/catalog/products/{id}/images
Reorder imagesPUT /api/admin/catalog/products/{id}/images/reorder
Delete imageDELETE /api/admin/catalog/products/{id}/images/{imageId}
List inventoriesGET /api/admin/catalog/products/{id}/inventories
Update inventoriesPUT /api/admin/catalog/products/{id}/inventories
List customer-group pricesGET /api/admin/catalog/products/{id}/customer-group-prices
Add customer-group pricePOST /api/admin/catalog/products/{id}/customer-group-prices
Update customer-group pricePUT /api/admin/catalog/products/{id}/customer-group-prices/{priceId}
Delete customer-group priceDELETE /api/admin/catalog/products/{id}/customer-group-prices/{priceId}

The canonical product listing is List products (GET /api/admin/catalog/products) above. There is also a separate slim Add-Product Search (GET /api/admin/products) used only by the Create-Order "Add Product" modal — not the product listing.

All Products endpoints require an admin Bearer token — see Authentication. Reads require catalog.products.view; writes require the matching catalog.products.create / .edit / .delete permission.

Released under the MIT License.