Catalog
Search, filter, and page through products, and show a product page with its variants.
Show the cotton T-shirts from your Lima store between S/ 40 and S/ 80, size M, in stock.
Requirements
- The store slug or a domain, in
x-Store-Domain. You don't need a token. - Products published in the store.
List products
GET /
returns one page of the published catalog.
curl "https://storefront.ecomiq.pe/v1/products?pageSize=24&sort=priceAsc&includeFilters=false" \
-H "x-Store-Domain: mi-tienda"{
"totalCount": 58,
"totalPages": 3,
"products": [
{
"id": "7204558912004322039",
"name": "Polo de algodón pima",
"slug": "polo-de-algodon-pima",
"url": "/products/polo-de-algodon-pima",
"imageUrl": "https://…/polo.webp",
"price": 59.9,
"compareAtPrice": 79.9,
"isAvailable": true
}
],
"filters": []
}The next examples reuse API and headers.
priceis the price of the cheapest variant. IfcompareAtPriceis higher, show it struck through.- With
isAvailable: false, no variant can be sold. Show "Sold out". - Link each product to its
url. Fetch its page withslug. - Without a filter panel, send
includeFilters=false:filterscomes back empty.
sort accepts priceAsc, priceDesc, newest, oldest, nameAsc,
nameDesc, and bestSelling. Without sort, recently edited products come
first. Within a single collection, without sort, products follow the
merchant's order.
Search by text
Send what the shopper typed in search.
curl -G https://storefront.ecomiq.pe/v1/products \
-H "x-Store-Domain: mi-tienda" \
--data-urlencode "search=polo algodón"- It searches name, description, brand, category, tags, SKU, barcode, and searchable specifications.
- Without
sort, results are ordered by relevance. - Combine it with filters. The filters in the response follow the search.
- To suggest products while the shopper types, use autocomplete.
Filter the catalog
Every filter is optional, and they combine. Copy the values from the
response's filters.
| Parameter | Filters by | Group in filters |
|---|---|---|
categoryId | One category, by id. Without subcategories. | — |
categories | Categories, by name. | category |
collectionId | One collection, by id. | — |
collections | Collections, by slug. | collection |
brands | Brands, by name. | brand |
tags | Tags. | tag |
productTypes | product, service, or bundle. | productType |
sellers | Sellers, by slug. | — |
productIds | Products, by id. Up to 100. | — |
minPrice, maxPrice | Price, in the store currency. | price |
inStock | true: in stock. false: sold out. | availability |
filters | Options and specifications. | option:…, attribute:… |
curl -G https://storefront.ecomiq.pe/v1/products \
-H "x-Store-Domain: mi-tienda" \
--data-urlencode "categories=Polos" \
-d "minPrice=40" -d "maxPrice=80" -d "inStock=true"- For several values, repeat the parameter:
brands=Andina&brands=Kuna. One match is enough. - A product matches when its variants' price range overlaps yours.
- With
productIds, the order is not the one you sent. Sort the list yourself.
Build the filters
Without includeFilters=false, the response includes filters: one group per
filter, with its values and counts.
{
"filters": [
{
"id": "price",
"label": "Price",
"type": "price_range",
"min": 29.9,
"max": 149.9,
"selectedMin": 40,
"selectedMax": 80
},
{
"id": "option:Talla",
"label": "Talla",
"type": "list",
"values": [
{ "value": "M", "count": 12, "label": "M", "selected": true },
{ "value": "L", "count": 10, "label": "L", "selected": false }
]
}
]
}When the shopper checks a value, send it in its group's parameter. In
availability, in_stock is inStock=true and out_of_stock is
inStock=false.
In filters, join the group id, :, and the value. For size M and cotton,
send filters=option:Talla:M and filters=attribute:Material:Algodón.
optiongroups are variant options.attributegroups are product specifications.- Pick one value per option. With two, you get a
400. - Several options must match the same variant. With
inStock=true, that variant is also in stock. - You can send several values of one
attribute. One match is enough. - Send up to 100
filters, each up to 250 characters. - Built-in groups have an English
label. Show your own text based onid. - If a value's
labelisnull, showvalue. - In
price,minandmaxignore your range.selectedMinandselectedMaxare yours. - Counts apply all your filters. Once you pick a brand,
brandonly lists that one. - Only options and specifications the merchant marked as filterable show up.
Page through results
Move page forward and keep the same filters and sort.
curl "https://storefront.ecomiq.pe/v1/products?categories=Polos&page=2&pageSize=24" \
-H "x-Store-Domain: mi-tienda"pagestarts at 1 and goes up to 100. Outside that range, you get a400.pageSizeis 24 if you don't send it. The maximum is 100.- After
totalPages,productscomes back empty. - With more than 100 pages, you can't reach the end. Raise
pageSizeor ask the shopper to filter.
Show a product
GET /
returns the full product page. Use the slug from the list.
curl https://storefront.ecomiq.pe/v1/products/polo-de-algodon-pima \
-H "x-Store-Domain: mi-tienda"{
"id": "7204558912004322039",
"name": "Polo de algodón pima",
"price": 59.9,
"compareAtPrice": 79.9,
"isAvailable": true,
"images": [{ "url": "https://…/polo.webp", "order": 1, "type": "image" }],
"specifications": [{ "name": "Material", "value": "Algodón" }],
"variants": [
{
"id": "7204558912004323197",
"price": 59.9,
"compareAtPrice": 79.9,
"quantity": 4,
"isAvailable": true,
"options": [
{ "key": "talla", "name": "Talla", "value": "M" },
{ "key": "color", "name": "Color", "value": "Azul", "color": "#1F3A93" }
]
},
{
"id": "7204558912004323198",
"isAvailable": false,
"options": [
{ "key": "talla", "name": "Talla", "value": "L" },
{ "key": "color", "name": "Color", "value": "Azul" }
]
}
]
}- The product page applies the store's active price lists. If it differs from the list, the product page wins.
priceandcompareAtPriceare those of the cheapest variant.- Sort
imagesbyorder.typeisimageorvideo: videos sit among the photos, where the merchant placed them. metafieldsholds only the metafields the store chose to show, withnameready to display andvalue.brandSlugleads to the brand page; it isnullwhen the product has no brand or the brand is inactive.specificationsis the spec sheet.sizeGuideis the size guide, ornull.priceTiersholds quantity prices:unitPricefromminQuantityon.- If the product doesn't exist or isn't published, you get a
404.
With the previewKey from the admin preview link, you see an unpublished
product. It comes with isPreview: true: don't cache it or index it.
Pick the variant
Build one selector per key in variants[].options: name is the title and
each value is a button. Then find the variant that matches all of them.
const groups = new Map();
for (const variant of product.variants) {
for (const option of variant.options) {
const group = groups.get(option.key) ?? { name: option.name, values: [] };
if (!group.values.includes(option.value)) group.values.push(option.value);
groups.set(option.key, group);
}
}
const selected = { talla: "M", color: "Azul" };
const variant = product.variants.find((item) =>
item.options.every((option) => selected[option.key] === option.value),
);
const canBuy = variant !== undefined && variant.isAvailable !== false;- If no variant matches, that combination doesn't exist. Disable it.
- With
isAvailable: false, the variant is sold out. Disable the buy button. - Check
isAvailable, notquantity. Without stock tracking or with backorders, a variant sells atquantity0. - Show the variant's
price,compareAtPrice, andimages. Withoutimages, use the product's. colorholds the hex code for the color swatch.- When the page opens, select the first available variant.
Add to cart
Send the variant id as variantId to
POST /.
The cart checks stock again. If there isn't enough, you get a 400 with
Catalog.InsufficientStock. Continue in Cart.
Show a brand
GET / returns the active brand with its logo (imageUrl), its
description, the search engine texts (metaTitle and metaDescription) and
productCount. If the brand doesn't exist or is inactive, you get a 404. To
list its products, filter the catalog with its name in brands. With GraphQL,
brand(slug:) returns the brand and products(input:) its products in the same
query.
GET / includes / for each active brand with visible
products. If your store builds its own sitemap, list those URLs only when it has
the brand page.
Errors
code | Status | What to do |
|---|---|---|
Common.Validation | 400 | Check errors: page, pageSize, filters, or sort is not valid, or a parameter has the wrong type. |
Common.BadRequest | 400 | x-Store-Domain is missing. |
Common.NotFound | 404 | The store or the collectionId collection doesn't exist or is inactive. |
Product.NotFound | 404 | The product doesn't exist, isn't published, or previewKey is invalid. |
Common.Unauthorized | 401 | The store is private. Ask for the password. |
Common.ServiceUnavailable | 503 | Search is not responding. Retry in a few seconds. |
Next steps
- Cart: add the variant and choose shipping.
- Menus and content: categories, collections, and private stores.
- Tracking and reviews: reviews and related products.
Last updated: