VenddorDocumentação API
API atualAPI legada
Guia rápidoReferência completa
Carregando índice…
API atual/Guia rápido/Lote, importação e exportação

Ações em lote

Muda status, preço, categoria, seller ou campos de muitos produtos, ou clona e exclui, em uma chamada, com simulação e desfazer.

Esta é a rota de lote unificada. O campo action escolhe o que fazer, e você escolhe os produtos com uma lista de ids ou com um filtro. Use quando a mesma mudança deve alcançar muitos produtos: ocultar uma marca inteira, subir os preços em 10%, mover uma lista de produtos para outra categoria, excluir os descontinuados.

Leia antes a visão geral para o fluxo simular, confirmar e desfazer e para a lista de chaves do filtro. O produto desta seção é identificado pelo UUID; o dinheiro é em centavos inteiros.

POST/api/v1/admin/products/bulkAdmin

Ação em lote sobre produtos

Exige o privilégio manage_catalog. O corpo é lido até 16 MiB. Não há número máximo fixo de ids, mas prefira um filter para mais do que alguns milhares de produtos.

actionO que fazCampos extrasDesfazível
update_statusDefine o status de todos os produtosstatusSim
update_categoryMove produtos para outra categoria (ela vira a categoria principal)category_idSim
update_priceMuda o preço de vendaprice_action, price_valueSim
deleteManda produtos para a lixeiranenhumSim (restaura)
cloneCria uma cópia de cada produtonenhumNão (exclua as cópias)
update_vendorAtribui os produtos a outro sellervendor_idNão
update_fieldEdita campos por transformação (acrescentar texto, trocar, somar um valor...)changesSim

Ações de preço em price_action (os nomes antigos absolute, increase, decrease, percentage_increase e percentage_decrease também são aceitos):

price_actionprice_valueResultado
set (ou set_fixed)centavosDefine o preço neste valor (maior que zero)
increase_fixedcentavosSoma este valor
decrease_fixedcentavosSubtrai este valor, nunca abaixo de zero
increase_percentpontos-base, de 0 a 10000Soma este percentual (500 = +5%)
decrease_percentpontos-base, de 0 a 10000Subtrai este percentual

price_value é obrigatório e não pode ser zero. Uma mudança que deixaria algum produto com preço zero é recusada para o lote inteiro.

update_field edita os campos name, sku, ean, brand, price_cents, list_price_cents, quantity, weight, length, width, height, status, seo_title e seo_description. Cada item de changes é {"field", "op", "value", "find"}:

Tipo do campoop permitidas
Texto (name, sku, ean, brand, seo_title, seo_description)set, append, prepend, replace (exige find), clear
Número (price_cents e list_price_cents em centavos, quantity, weight, length, width, height)set, increase, decrease
statusset

update_field sempre passa pelo fluxo de simular e confirmar, mesmo com lista de ids. Os campos de produtos ligados a um produto mestre seguem as regras de campos editáveis do mestre, e as linhas que não podem mudar vêm em failed.

Corpo da requisição

actionstringobrigatório
update_statusupdate_categoryupdate_pricedeletecloneupdate_vendorupdate_field
O que fazer.
product_idsarrayobrigatório
UUIDs dos produtos. Obrigatório, a menos que você mande filter. Cada id precisa ser um UUID.
filterobject
Seleciona os produtos no servidor (veja a tabela de chaves na visão geral). Quando presente, product_ids é ignorado. Exige o fluxo de simular e confirmar.
simulatebooleanpadrão: false
Simulação: nada é gravado.
confirm_tokenstring
Token devolvido pela simulação do mesmo corpo. Obrigatório para executar um lote por filter.
statusstring
ADHactivedisabledhiddeninactive
Novo status para update_status. R e X são recusados aqui.
category_iduuid
Categoria de destino para update_category. Precisa existir e não estar na lixeira.
vendor_iduuid
Seller de destino para update_vendor. Precisa ser um seller ativo.
price_actionstring
setset_fixedincrease_fixeddecrease_fixedincrease_percentdecrease_percent
Tipo de mudança de preço para update_price.
price_valueinteger
Valor para update_price: centavos, ou pontos-base nas ações de percentual.
changesarray
Lista de edições de campo para update_field, uma entrada por campo.

Exemplo de requisição

Simule um aumento de 10% em todos os produtos ativos de uma marca e depois execute com o token.

bash
# 1) simular
curl -X POST "$BASE_URL/api/v1/admin/products/bulk" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "action": "update_price",
    "price_action": "increase_percent",
    "price_value": 1000,
    "filter": { "brand": "acme", "status": "active" },
    "simulate": true
  }'

# 2) executar: mesmo corpo, sem "simulate", com o confirm_token do passo 1
curl -X POST "$BASE_URL/api/v1/admin/products/bulk" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "action": "update_price",
    "price_action": "increase_percent",
    "price_value": 1000,
    "filter": { "brand": "acme", "status": "active" },
    "confirm_token": "eyJ0IjoiZGZl..."
  }'

Resposta

200Simulação de um lote por filtro
json
{
  "simulate": true,
  "action": "update_price",
  "description": "Aumentar o preço dos produtos em 10%",
  "total": 2,
  "sample": [
    { "id": "a34f126e-ff3b-4779-bf74-bda03502136e", "name": "Caneca Azul", "before": "R$ 49,90", "after": "R$ 54,89" },
    { "id": "ea4e5a3d-bed2-4bcc-bce4-53a8370cee28", "name": "Camiseta Azul", "before": "R$ 49,90", "after": "R$ 54,89" }
  ],
  "confirm_token": "eyJ0IjoiZGZl...",
  "expires_at": "2026-10-11T22:04:00Z",
  "async": false,
  "by": "filter"
}
200Lote por filtro concluído (menos de 50 registros)
json
{
  "action": "update_price",
  "by": "filter",
  "total_requested": 2,
  "status": "done",
  "affected": 2,
  "failed": [],
  "undo_id": "ad40a3ab-042f-4495-bb33-c44cb51cfdff"
}
202Lote por filtro em segundo plano (50 registros ou mais)
json
{
  "action": "update_price",
  "by": "filter",
  "total_requested": 5000,
  "status": "running",
  "async": true,
  "job": {
    "id": "7c1b6f0e-2d0e-4c6e-9d3a-0d6c1f6a9b11",
    "status": "running",
    "total": 5000,
    "processed": 0,
    "affected": 0,
    "failed": 0,
    "percent": 0
  }
}
200Lista de ids, executado de verdade
json
{ "action": "update_status", "affected": 2, "undo_id": "5b1d9f9c-4f55-4a70-bd2d-2d6c7e5d2f10" }
200Lista de ids, simulação
json
{
  "action": "update_status",
  "simulate": true,
  "total_affected": 0,
  "preview": [
    { "product_id": "ea4e5a3d-bed2-4bcc-bce4-53a8370cee28", "name": "Camiseta Azul", "current_value": "A", "new_value": "H", "ok": true },
    { "product_id": "00000000-0000-0000-0000-000000000000", "ok": false, "reason": "not_found" }
  ]
}
200clone e update_vendor com lista de ids
json
{ "action": "clone", "cloned": 1, "products": [{ "id": "81f223bc-9dec-4a0a-9c40-4263ac893973", "name": "Camiseta Azul (Copy)", "status": "R" }] }
json
{ "action": "update_vendor", "affected": 3 }

Campos da resposta

simulateboolean
true nas simulações.
totalinteger
(simulação por filtro) Quantos produtos o filtro alcança.
samplearray
(simulação por filtro) Até 10 produtos com id, name, before e after. Os preços da amostra vêm formatados para leitura (R$ 54,89).
confirm_tokenstring
(simulação por filtro) Devolva-o com o mesmo corpo para executar. Vale 70 minutos.
expires_atstring
(simulação por filtro) Validade do token em RFC 3339.
asyncboolean
true quando a execução criará uma tarefa em segundo plano (50 registros ou mais).
notestring
Presente quando o filtro não alcança nenhum produto ("nada será alterado").
previewarray
(simulação por ids) Uma linha por id: product_id, name, current_value, new_value (textos; preço em centavos, categoria como UUID), ok, e reason (not_found) quando ok é falso.
total_affectedinteger
(simulação por ids) Sempre 0: nada foi gravado.
total_requestedinteger
(execução por filtro) Quantos produtos o lote alcançou.
statusstring
(execução por filtro) done, ou queued/running quando assíncrono.
affectedinteger
Quantos produtos mudaram.
failedarray
(execução por filtro) Produtos que não mudaram, cada um {id, error}.
partial_failureboolean
(execução por filtro) true quando alguns produtos falharam. Uma message diz quantos.
undo_idstring
Id do retrato para POST /api/v1/admin/bulk-undo/{undo_id}. Ausente em clone e update_vendor. Em tarefa em segundo plano fica em job.result.
jobobject
(assíncrono) A tarefa: id, status, total, processed, affected, failed, percent, errors, result, created_at, started_at, finished_at.
clonedinteger
(clone) Número de cópias. products as lista. A cópia não tem SKU e nasce com status R (aguardando revisão), então não aparece na loja.

Erros

StatusQuandoExemplo de corpo
400Corpo não é JSON válido{"error":"invalid request body","detail":"invalid character 'b' looking for beginning of object key string"}
400Sem ids e sem filtro{"error":"product_ids is required and must not be empty"}
400Ação desconhecida{"error":"invalid action","detail":"action must be one of: update_status, delete, clone, update_category, update_price, update_vendor"}
400Um id não é UUID{"error":"invalid product_ids","detail":"... \"abc\" não é um uuid de produto ..."}
400Status não aceito em lote (R, X, desconhecido){"error":"invalid product status","detail":"invalid product status: R (must be A/D/H or active/hidden/disabled/inactive/pending)"}
400price_action desconhecida{"error":"invalid price_action","detail":"must be one of: set, increase_fixed, decrease_fixed, increase_percent, decrease_percent"}
400price_value ausente ou zero{"error":"price_value is required for update_price action","detail":"..."} ou {"error":"price_value cannot be zero",...}
400Preço fora da faixa, ou a mudança deixaria um produto em zero{"error":"invalid bulk price update","detail":"percentage must be between 0 and 10000 (basis points)"}
400Chave de filtro desconhecida, filtro vazio, changes inválido{"error":"invalid_filter","detail":"filtro de lote inválido: chave \"colour\" não existe ... Chaves aceitas: ..."}
400category_id não é UUID{"error":"invalid bulk category move","detail":"..."}
401Sem token ou token inválido{"error":"missing authorization header"}
403Sem manage_catalog{"error":"insufficient privileges","required":"manage_catalog"}
404Categoria de destino não existe ou está na lixeira{"error":"category not found","detail":"nenhuma categoria ativa com o id ..."}
409Token de outro corpo, expirado, ou o filtro agora alcança mais registros{"error":"confirm_token_invalid","detail":"confirm_token não vale para este pedido: ..."}
428Lote por filtro sem confirm_token{"error":"simulate_required","detail":"lote por filtro exige simulação: ..."}
500update_vendor com seller inexistente ou inativo, ou qualquer falha do servidor{"error":"failed to bulk update vendor","detail":"vendor not found or not active"}

Os textos de detail são escritos em português pelo servidor e voltam como estão.

update_vendor e clone não têm desfazer e ignoram simulate no caminho por ids

Com lista de ids, simulate: true é respeitado por update_status, update_category, update_price e delete, mas clone e update_vendor executam de verdade. Para simulá-los, mande os ids como filtro: "filter": {"ids": ["..."]} com "simulate": true. Trocar o seller não pode ser desfeito: anote antes o vendor_id anterior de cada produto.

Excluir manda para a lixeira, e o desfazer restaura

delete é exclusão lógica: os produtos saem do catálogo e da loja e aparecem na lixeira. POST /api/v1/admin/bulk-undo/{undo_id} os traz de volta. Desfazer duas vezes devolve 409 already undone.

Desfazer

POST /api/v1/admin/bulk-undo/{undo_id} com corpo vazio {} desfaz na hora e responde {"total":2,"ok":2}. Com {"simulate": true} ele mostra antes o que voltaria e um confirm_token, como qualquer lote por filtro. A lista de lotes que podem ser desfeitos é GET /api/v1/admin/bulk-undo.

Veja também

  • Rotas de lote dedicadas
  • Edição estilo planilha
  • Alterar um produto
  • Excluir um produto
Anterior
Lote, importação e exportação
Próxima
Rotas de lote dedicadas
Nesta página
  • Exemplo de requisição
  • Resposta
  • Erros
  • Veja também