Categories and collections
Organize the catalog with categories, brands, collections, attributes, and size guides.
Organize the catalog of a clothing store in Lima: the category Ropa > Polos, the brand "Andes", the "Verano" collection, a material attribute, and a size guide for the polo shirts.
Requirements
- An Admin token with the
catalog:create,catalog:read,catalog:update, andcatalog:deletepermissions inECOMIQ_TOKEN. See Quickstart. - A product. See Variants and prices.
Create the categories
First create Ropa with { "name": "Ropa" }. Then create Polos with the id of
Ropa in parentId.
curl -X POST https://api.ecomiq.pe/api/v1/catalog/categories \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Polos", "parentId": "7204558912004325501" }'The API responds 201 with the id. The next steps reuse call.
- Without
slug, one is generated fromname. It is unique across the store, even for categories with different parents. ordersorts sibling categories, lowest first.
Arrange the tree
GET / returns every category in order, each with
its children in children and its route in path (ropa/).
To move or reorder, send the tree with PUT. If you later create Casacas, this
example puts it before Polos. The API responds 200 with true.
curl -X PUT https://api.ecomiq.pe/api/v1/catalog/categories/tree \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "categories": [{
"id": "7204558912004325501",
"children": [{ "id": "7204558912004325503" }, { "id": "7204558912004325502" }]
}] }'- Nesting sets the parent, and the position in each list sets
order. TheparentIdandorderof each node are ignored. - Top-level nodes become root categories. Categories you leave out don't change.
PUT replaces the category
PUT / can also move a category to another
parentId, but it replaces it whole: if you omit parentId, order,
description, logo, icon, requiresSizeGuide, or the commissions, they
reset to their defaults. Without slug, a new one is generated from name.
Create the brand
curl -X POST https://api.ecomiq.pe/api/v1/catalog/brands \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Andes", "logo": "https://cdn.mitienda.pe/marcas/andes.png" }'The API responds 201 with the id.
- Without
slug, one is generated fromname. It is unique across the store. logoandiconmust be absolute URLs.PUT /replaces the name,v1/ catalog/ brands/ {brandId} slug, images, description, and order.
Assign category and brand
Send categoryId and brandId when you
update the product, or when
you create it. This example also adds the verano tag.
curl -X PATCH https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302 \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "categoryId": "7204558912004325502", "brandId": "7204558912004325510", "tags": ["verano"] }'{
"id": "7204558912004325302",
"tags": ["verano"],
"category": {
"id": "7204558912004325502",
"name": "Polos",
"path": "ropa/polos"
},
"brand": { "id": "7204558912004325510", "name": "Andes" }
}- A product has one category and one brand.
- To remove them, send
clearCategory: trueorclearBrand: trueinstead.
Create an automatic collection
A dynamic collection fills itself with the products that match its rules.
"Verano" groups the polos tagged verano and pins one at the top. With and,
a product must match every rule; with or, one is enough.
{
"name": "Verano",
"type": "dynamic",
"status": "active",
"dynamicOperator": "and",
"rules": [
{ "field": "categoryId", "operator": "eq", "value": "7204558912004325502" },
{ "field": "tag", "operator": "eq", "value": "verano" }
],
"pins": [{ "productId": "7204558912004325302", "position": 0 }]
}curl -X POST https://api.ecomiq.pe/api/v1/catalog/collections \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
--data @verano.jsonThe API responds 201 with the id.
| To include | Rule |
|---|---|
| Several brands | { "field": "brand", "operator": "in", "value": "<id>,<id>" } |
| Under S/ 100 | { "field": "price", "operator": "lt", "value": "100" } |
| A word in the title | { "field": "title", "operator": "contains", "value": "pima" } |
valueis always a string. WithinandnotIn, separate up to 100 values with commas.categoryIdmatches the product's own category, not its subcategories.includeProductIdsadds products.excludeProductIdsremoves them, even if they match the rules or are pinned.
The collection fills in the background, and only while it is active and
within validFrom and validTo. Its products, with sortOrder and
isPinned, are in GET /.
To edit, send everything
PUT / replaces the collection. Without
type, it becomes static and loses its rules and products. Without
status, it goes back to draft.
Create a manual collection
A static collection holds only the products you choose. Create it and send
the list. The PUT responds 204.
curl -X POST https://api.ecomiq.pe/api/v1/catalog/collections \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Regalos", "type": "static", "status": "active" }'
curl -X PUT https://api.ecomiq.pe/api/v1/catalog/collections/7204558912004325521/products \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "productIds": ["7204558912004325302", "7204558912004325303"] }'- The list replaces the previous one, and its order is the collection's order. IDs that don't exist are ignored.
- To add or remove products without sending the whole list, use
POST /.v1/ catalog/ products/ batch/ collections
Define an attribute
An attribute (specification) describes the product, such as its material. With
type: "select", it only accepts its values: each one has a value that
identifies it and a name that is displayed.
curl -X POST https://api.ecomiq.pe/api/v1/catalog/specifications \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Material", "key": "material", "type": "select",
"values": [{ "value": "algodon-pima", "name": "Algodón pima" }, { "value": "lino", "name": "Lino" }]
}'The API responds 201 with the id. The product stores its value in
specifications, with the attribute's key:
curl -X PATCH https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302 \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "specifications": [{ "key": "material", "name": "Material", "value": "algodon-pima" }] }'keyaccepts letters, numbers,-, and_. It is stored in lowercase and is unique across the store.specificationsreplaces the product's list. Akeythat doesn't exist creates a new text attribute.- If the value is not one of the attribute's options, the API responds
409.
To edit, send everything
PUT / replaces the attribute. Always send
type: without it, the API assumes input. In values, send the options you
keep with their id and new ones without id. A missing option is deleted;
if it is in use, the API responds 409.
Require the attribute in a category
Link Material to Polos and make it required. The API responds 204. The list
replaces the previous one, and GET on the same path returns it.
curl -X PUT https://api.ecomiq.pe/api/v1/catalog/categories/7204558912004325502/specifications \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "specifications": [{ "specificationId": "7204558912004325530", "isRequired": true }] }'- It takes up to 100 active attributes, with
levelproductorall. - A Polos product in
activeoroutOfStockneeds that value, or the API responds409when you save it. Only its own category counts. - Only categories require attributes: a product without a category has none.
Create the size guide
A guide is a table of measurements per size. Assign it on creation with
assignments.
{
"name": "Polos unisex",
"status": "active",
"rows": [
{
"label": "S",
"sizeKey": "S",
"order": 0,
"measurements": [
{
"key": "pecho",
"name": "Pecho",
"min": 86,
"max": 91,
"value": null,
"description": null
}
]
},
{
"label": "M",
"sizeKey": "M",
"order": 1,
"measurements": [
{
"key": "pecho",
"name": "Pecho",
"min": 92,
"max": 97,
"value": null,
"description": null
}
]
}
],
"assignments": [
{ "targetType": "category", "targetId": "7204558912004325502" }
]
}curl -X POST https://api.ecomiq.pe/api/v1/catalog/size-guides \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
--data @guia-polos.jsonThe API responds 201 with the id.
- Only
activeguides apply. Withoutstatus, the guide stays indraft. - It needs
rowsorimageUrl. Each row and measurement carries all its fields, even if they arenull. - Without
gender,measurementType, orunit, they default tounisex,body, andcm. If another active guide with the samegenderandmeasurementTypeis on that product or category, the API responds409.
To edit, send everything
PUT / replaces the data and rows, and
keeps the assignments. Without status, the guide goes back to draft and
stops applying.
Assign the guide
The closest assignment wins: the product's own, then its category's, then a
parent category's with includeChildrenCategories: true. Between guides at the
same level, the higher priority wins.
# A product's own guide. Responds 204. With null, you remove it.
curl -X PUT https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302/size-guide \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "sizeGuideId": "7204558912004325540" }'
# A category and its children. Responds 201 with the assignment id.
curl -X POST https://api.ecomiq.pe/api/v1/catalog/size-guides/7204558912004325540/assignments \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "targetType": "category", "targetId": "7204558912004325501", "includeChildrenCategories": true }'GET / responds 200 with the guide
that applies, or 204 if none does. To remove an assignment, use
DELETE /.
Delete what you don't use
Each DELETE responds 204.
| Resource | Path | Deleted if |
|---|---|---|
| Category | / | It has no subcategories or products. |
| Brand | / | No product uses it. |
| Attribute | / | No category, product, or variant uses it. |
| Collection | / | Always. Products don't change. |
| Size guide | / | Always. It leaves the products that used it. |
GET / tells you how many products and
variants use an attribute, and which categories have it.
Import and export
Categories, brands, collections, and size guides also move by file, through
/ and /. They respond 202 with an operation: follow it as in
Product import. When an export
finishes, resultUrl has the file.
Errors
code | Status | What to do |
|---|---|---|
Common.Validation | 400 | Check errors: a field is missing or malformed. |
Category.SlugExists, Brand.SlugExists, Collection.SlugExists, Collection.Exists, SizeGuide.SlugExists | 409 | Another resource uses that slug or name: change it. |
Category.ParentNotFound | 404 | The parentId doesn't exist in the store. |
Category.CircularReference, Categories.InvalidHierarchy | 400 | A category can't end up inside itself. |
Category.HasSubcategories, Category.HasProducts, Brand.HasProducts | 409 | Move the subcategories or products before deleting. |
Product.CategoryNotFound, Product.BrandNotFound | 404 | Check the category or brand ID. |
Collection.InvalidType | 400 | Only static collections take products by hand. |
Specification.AlreadyExists | 409 | Another attribute uses that key or alias. |
Specification.ValueInUse | 409 | Change that value on the products before removing it. |
Specification.HasCategorySpecifications, Specification.InUseByProducts, Specification.InUseByVariants | 409 | Remove the attribute from categories, products, and variants before deleting it. |
Category.Specifications | 400 | An attribute is repeated, missing, inactive, or not for products. |
SizeGuideAssignment.Conflict | 409 | A compatible guide already targets that product or category. |
SizeGuide.Inactive | 400 | Activate the guide before assigning it to a product. |
Common.Conflict | 409 | Read detail: a required attribute is missing or a value is invalid. |
Next steps
Last updated: