Skip to content
Catalog

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, and catalog:delete permissions, depending on what you do.
  • The operation:read permission, 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:

Response
{
  "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 as draft: 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. Without slug, it's built from the name.
  • To show a struck-through price, send compareAtPrice, higher than price.
  • 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"
Response
{
  "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.

ParameterWhat it filters
status, excludeStatusStatuses. Without them, archived products are left out.
includeArchived=trueAdds archived products.
categoryIds, brandIdsThe product's category or brand. Subcategories don't count.
tagsTags that contain the text, ignoring case.
skusExact SKU of a variant.
minPrice, maxPriceProduct price: the lowest of its active variants.
minAvailableUnits available, adding up its active variants.
  • Sort with sortBy: createdOn (default), updatedOn, name, price, available, onHand, or salesCount. sortDirection defaults to desc.
  • limit goes from 1 to 200. The default is 20.
  • If hasNextPage is true, repeat the call with cursor set to nextCursor. Keep the same filters and sort order.
  • totalCount only comes on the first page, with includeTotalCount=true.
  • With includeVariants=true, each product brings its variants.

To know how many there are without fetching them, call /count 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:

Response
{
  "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" }]
    }
  ]
}
  • price is the lowest price among active variants. available adds up their available units.
  • Each variant has its price, its stock, and its options, such as the size. Deleted variants don't appear.
  • category and brand are null when 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 empty name is ignored.
  • tags, images, and specifications replace the current list. With [], you empty it.
  • Changing name doesn't change the slug. If you want a new one, send slug.
  • To remove the brand or the category, send clearBrand or clearCategory as true. See Categories and collections.
  • The product's price and compareAtPrice only 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 variantId and deleted: 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: true or clearCostPrice: true. Here null removes nothing, and a flag sent with a price is rejected.
  • To detect concurrent changes, send expectedVersion on 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.

statusIn the store
draftHidden. This is the status on creation.
activeVisible and for sale.
outOfStockVisible, but can't be bought. Set automatically.
inactiveHidden.
archivedHidden. It's also left out of the list without includeArchived=true.
  • If you send outOfStock, it's ignored. discontinued can't be set through the API.
  • Archiving sets its variants to inactive. If you reactivate the product, activate them with PATCH /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 /v1/catalog/products/batch/...:

  • status: changes the status.
  • tags: adds or removes tags with addTags and removeTags, up to 100.
  • collections: adds them to or removes them from manual collections, with addCollectionIds and removeCollectionIds.
  • 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 responds 200 with the result for each one. For prices, use items, also up to 100.
  • With filters, no cap. They are the list filters, in JSON. The API responds 202 with 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" }'
Response
{
  "results": [
    {
      "index": 0,
      "id": "7204558912004325302",
      "status": "updated",
      "errors": []
    },
    {
      "index": 1,
      "id": "7204558912004325303",
      "status": "failed",
      "errors": [
        { "field": null, "code": "Product.NotFound", "message": "Not found." }
      ]
    }
  ]
}
  • index is the position in ids. status is updated, deleted, or failed.
  • 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_large when 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 /count with exact=true:

/batch/delete body
{ "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

codeStatusWhat to do
Common.Validation400Check errors: a field is missing or has the wrong format.
Catalog.Products.PlanLimitReached400You hit your plan's limit: delete products or change plans.
Products.BatchDeleteCountMismatch400The catalog changed: count again and resend expectedCount.
Common.Forbidden403Add the missing permission to your app.
Product.NotFound404The product doesn't exist in the store or was deleted.
Product.BrandNotFound, Product.CategoryNotFound404Check the brand or category ID.
Product.VariantNotFound404A variantId in variants doesn't belong to this product.
Product.AlreadyExists, Product.SlugExists409Another product uses that slug: change it.
Product.VariantSkuExists409Another variant already uses that SKU: change it.

Next steps

Last updated:

On this page