Products
Create, find, edit, publish, and delete products with the Admin API, one at a time or in bulk.
Create the "Polo de algodón" for your Lima store at S/ 59.90 and manage it from the Admin API.
Requirements
- An Admin token in
ECOMIQ_TOKEN. See Quickstart. - The
catalog:create,catalog:read,catalog:update, andcatalog:deletepermissions, depending on what you do. - The
operation:readpermission, to follow filtered bulk actions and exports.
Create a product
Send the name and the price. Everything else is optional.
curl -X POST https://api.ecomiq.pe/api/v1/catalog/products \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Polo de algodón", "sku": "POL-001", "price": 59.90 }'The API responds 201 with the full product. Keep its id:
{
"id": "7204558912004325302",
"name": "Polo de algodón",
"slug": "polo-de-algodon",
"status": "draft",
"price": 59.9,
"variants": [
{ "id": "7204558912004325377", "sku": "POL-001", "trackInventory": true }
]
}- Without
status, the product starts asdraft: it doesn't show in the store. - Without
variants, one variant is created with the product's SKU and price. - Without
sku, one is generated. Withoutslug, it's built from the name. - To show a struck-through price, send
compareAtPrice, higher thanprice. - For sizes or colors, follow Variants and prices.
Find products
List your products with filters. This example finds draft polos:
curl "https://api.ecomiq.pe/api/v1/catalog/products?search=polo&status=draft&sortBy=name" \
-H "Authorization: Bearer $ECOMIQ_TOKEN"{
"data": [{ "id": "7204558912004325302", "name": "Polo de algodón" }],
"hasNextPage": false,
"nextCursor": null,
"totalCount": null
}search looks in the name, the description, the SKUs, and the barcodes. It
ignores case. For several values, repeat the parameter:
status=draft&status=active.
| Parameter | What it filters |
|---|---|
status, excludeStatus | Statuses. Without them, archived products are left out. |
includeArchived=true | Adds archived products. |
categoryIds, brandIds | The product's category or brand. Subcategories don't count. |
tags | Tags that contain the text, ignoring case. |
skus | Exact SKU of a variant. |
minPrice, maxPrice | Product price: the lowest of its active variants. |
minAvailable | Units available, adding up its active variants. |
- Sort with
sortBy:createdOn(default),updatedOn,name,price,available,onHand, orsalesCount.sortDirectiondefaults todesc. limitgoes from 1 to 200. The default is 20.- If
hasNextPageistrue, repeat the call withcursorset tonextCursor. Keep the same filters and sort order. totalCountonly comes on the first page, withincludeTotalCount=true.- With
includeVariants=true, each product brings its variants.
To know how many there are without fetching them, call / with the same
filters:
curl "https://api.ecomiq.pe/api/v1/catalog/products/count?status=draft" \
-H "Authorization: Bearer $ECOMIQ_TOKEN"The response has total and precision. It counts up to 10,000 products: past
that, precision is atLeast and total is a minimum. Send exact=true for
the exact number.
Read the details
Request the product by its id:
curl https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302 \
-H "Authorization: Bearer $ECOMIQ_TOKEN"This is the polo once it has sizes, a category, a brand, a photo, and stock:
{
"id": "7204558912004325302",
"name": "Polo de algodón",
"status": "active",
"price": 59.9,
"available": 24,
"category": { "id": "7204558912004325502", "name": "Polos" },
"brand": { "id": "7204558912004325510", "name": "Andes" },
"images": [{ "url": "https://cdn.mitienda.pe/polo.webp", "isPrimary": true }],
"variants": [
{
"id": "7204558912004325377",
"sku": "POL-001-S",
"price": 59.9,
"available": 10,
"options": [{ "name": "Talla", "key": "talla", "value": "S" }]
}
]
}priceis the lowest price among active variants.availableadds up their available units.- Each variant has its price, its stock, and its
options, such as the size. Deleted variants don't appear. categoryandbrandarenullwhen the product has none.
Edit a product
Send only the fields you change:
curl -X PATCH https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302 \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "description": "Algodón pima peruano.", "tags": ["polos", "verano"] }'The API responds 200 with the full product, as in the details.
- What you leave out, or send as
null, doesn't change. - To empty a text such as
description, send"". An emptynameis ignored. tags,images, andspecificationsreplace the current list. With[], you empty it.- Changing
namedoesn't change theslug. If you want a new one, sendslug. - To remove the brand or the category, send
clearBrandorclearCategoryastrue. See Categories and collections. - The product's
priceandcompareAtPriceonly apply to bundles (bundle). For other products, change each variant's price.
Variants
In variants, send only the variants you change:
- With
variantId, you update that variant. Omitted fields keep their value. - Without
variantId, you create a new one. - With
variantIdanddeleted: true, you delete it. - Variants you don't send don't change. With
[], nothing changes. - To remove the compare-at price or the cost, send
clearCompareAtPrice: trueorclearCostPrice: true. Herenullremoves nothing, and a flag sent with a price is rejected. - To detect concurrent changes, send
expectedVersionon the product and on each variant. - A bundle only lets you update its existing variant. Change its components in
items.
Change the status
Publish the polo with status:
curl -X PATCH https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302 \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'The polo tracks stock and has no units yet. So the response has
"status": "outOfStock". When you load stock in
Inventory, it turns active on its own.
status | In the store |
|---|---|
draft | Hidden. This is the status on creation. |
active | Visible and for sale. |
outOfStock | Visible, but can't be bought. Set automatically. |
inactive | Hidden. |
archived | Hidden. It's also left out of the list without includeArchived=true. |
- If you send
outOfStock, it's ignored.discontinuedcan't be set through the API. - Archiving sets its variants to
inactive. If you reactivate the product, activate them withPATCH /.v1/ catalog/ variants/ {variantId}
Delete a product
curl -X DELETE https://api.ecomiq.pe/api/v1/catalog/products/7204558912004325302 \
-H "Authorization: Bearer $ECOMIQ_TOKEN"The API responds 204. The product and its variants are deleted: its GET now
responds 404.
- Orders don't change: each line keeps its own copy of the name, SKU, and price.
- Its SKUs become free for another product.
- You can't undo it. If you only want it out of the store, archive it.
Work in bulk
Change many products with POST /:
status: changes the status.tags: adds or removes tags withaddTagsandremoveTags, up to 100.collections: adds them to or removes them from manual collections, withaddCollectionIdsandremoveCollectionIds.prices: changes prices. See Variants and prices.delete: deletes them.
Pick the products with ids or with filters, never both:
- With
ids, up to 100. The API responds200with the result for each one. Forprices, useitems, also up to 100. - With
filters, no cap. They are the list filters, in JSON. The API responds202with an operation: follow it as in Product import.
This example archives two products:
curl -X POST https://api.ecomiq.pe/api/v1/catalog/products/batch/status \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ids": ["7204558912004325302", "7204558912004325303"], "status": "archived" }'{
"results": [
{
"index": 0,
"id": "7204558912004325302",
"status": "updated",
"errors": []
},
{
"index": 1,
"id": "7204558912004325303",
"status": "failed",
"errors": [
{ "field": null, "code": "Product.NotFound", "message": "Not found." }
]
}
]
}indexis the position inids.statusisupdated,deleted, orfailed.- Each product is saved on its own: if one fails, the rest still apply.
- A product with more than 1,000 variants fails with
resource_too_largewhen you change its status or delete it.
An empty filter selects everything
With "filters": {}, the change reaches every product that isn't archived.
To delete with filters, send expectedCount: how many products you expect to
delete. If it doesn't match, nothing is deleted. Get that number from /
with exact=true:
{ "filters": { "status": ["archived"] }, "expectedCount": 24 }Export the catalog
curl -X POST https://api.ecomiq.pe/api/v1/catalog/products/exports \
-H "Authorization: Bearer $ECOMIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "format": "csv", "status": ["active"] }'The API responds 202 with an operation. When it finishes, resultUrl has the
file. format is csv or xlsx; without it, you get xlsx. The filters are
the same as in the list.
Each row represents a variant. Its options appear in Option N name and
Option N value pairs, with as many pairs as the largest number of options on
any selected product, in each product's option order. Variants without options
leave those cells empty. If no products have options, there are no option
columns. The empty template ("template": true) includes three pairs; you can
add more.
You can import the file again to edit the catalog. Updating one option preserves omitted options. See Product import for the accepted headers and pair validation rules.
Errors
code | Status | What to do |
|---|---|---|
Common.Validation | 400 | Check errors: a field is missing or has the wrong format. |
Catalog.Products.PlanLimitReached | 400 | You hit your plan's limit: delete products or change plans. |
Products.BatchDeleteCountMismatch | 400 | The catalog changed: count again and resend expectedCount. |
Common.Forbidden | 403 | Add the missing permission to your app. |
Product.NotFound | 404 | The product doesn't exist in the store or was deleted. |
Product.BrandNotFound, Product.CategoryNotFound | 404 | Check the brand or category ID. |
Product.VariantNotFound | 404 | A variantId in variants doesn't belong to this product. |
Product.AlreadyExists, Product.SlugExists | 409 | Another product uses that slug: change it. |
Product.VariantSkuExists | 409 | Another variant already uses that SKU: change it. |
Next steps
- Variants and prices: sizes, colors, and bulk prices.
- Inventory: load stock so you can sell.
- Product import: upload the catalog from a file.
Last updated: