Anúncio vs Produto¶
A distinção entre produto e anúncio é central na modelagem Gubee. Confundir os dois leva a erros como atualizar preço no produto quando o desejado era no anúncio, ou esperar que uma edição no catálogo reflita instantaneamente na publicação.
O que é um produto?¶
Um produto é a entidade de catálogo. Tem:
- Um
externalId(também chamadoproductId), definido pelo seller. - Metadados (título, descrição, marca, dimensões, NBM).
- N variações, cada uma com seu próprio
sku(do seller) eskuId(Gubee). - Imagens e vídeos por variação.
- Atributos e categorias.
- EANs por variação: a lista
eans, com um principal (ean, depreciado, devolve o principal).
Rotas canônicas: /integration/products/*.
O produto não está associado a um marketplace específico. Ele é a "fonte da verdade" do catálogo.
O que é um anúncio?¶
Um anúncio é a publicação do produto em um marketplace específico. Tem:
- Um
adId(gerado pela Gubee). - Um
originSkuIdque aponta para a variação do produto que o originou. - Um
platform(MERCADOLIVRE,SHOPEE, etc.). - Título e descrição enriquecidos por template (podem diferir do produto).
- Preço, estoque e imagens específicos da publicação.
- Status (
ACTIVE,INACTIVE,PAUSED).
Rotas canônicas: /integration/ads/* e /bffweb/ads/*.
Relação: 1 produto → N anúncios¶
Para um produto com N variações publicado em M marketplaces, existem até N×M anúncios. Cada anúncio é independente: preço e estoque podem variar por marketplace, mesmo que o produto subjacente seja o mesmo.
PRODUTO (productId=PROD-001)
/ | \
var skuId-A var skuId-B var skuId-C
| | |
+------+------+ +----+----+ +------+------+
| | | | | | | |
ML SHOPEE B2W ML SHOPEE ML SHOPEE B2W
| | | | | | | |
ad#1 ad#2 ad#3 ad#4 ad#5 ad#6 ad#7 ad#8
Cada ad#N tem seu próprio adId e seu próprio preço/estoque.
Replicação produto → anúncio¶
Quais campos do produto acompanham o anúncio depois de criado é controlado pelo campo
updateOptions do anúncio. Cada opção cobre um campo ou um grupo de campos:
| Opção | Campos do anúncio atualizados |
|---|---|
TITLE |
título |
DESCRIPTION |
descrição |
DIMENSIONS |
altura, largura, profundidade e peso |
HANDLING_TIME |
prazo de manuseio |
IMAGES |
imagens da variação |
VIDEOS |
vídeos da variação |
STATUS |
ativo/inativo |
PRICE |
preço |
SPECIFICATION |
especificações/atributos |
EAN |
EAN/GTIN: ean e a lista eans, sempre os dois juntos |
BRAND |
marca — usa o nome do de/para da marca no marketplace do anúncio; sem de/para, o nome da marca |
FISCAL |
NCM, origem fiscal e país de origem (sempre os três juntos) |
WARRANTY |
garantia: tempo e tipo (SELLER_WARRANTY / FACTORY_WARRANTY), sempre os dois juntos; tipo não informado no produto não altera o do anúncio |
CONDITION |
condição (novo/usado) |
Quando a opção está no set, a mudança no produto chega ao anúncio via plataforma de streaming
de eventos. Renomear uma marca, ou alterar o de/para dela com um marketplace, atualiza todos os
anúncios com BRAND dos produtos daquela marca. Sem a opção, o anúncio mantém o valor próprio.
O anúncio só leva o campo ao marketplace se a integração daquele canal publica esse campo.
Clientes devem ignorar valores desconhecidos de updateOptions: novas opções podem ser
acrescentadas sem aviso de versão.
Ligar ou desligar opções¶
Atenção: este endpoint está em
/bffweb(superfície web), não em/integration. Parceiros ERP/hub raramente precisam tocá-lo — a replicação é normalmente configurada via painel.
curl -X PUT "$GUBEE_API/bffweb/ads/update/updateOptions" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"adIds": ["ad#1", "ad#2"],
"eventOptions": ["BRAND", "FISCAL"],
"action": "ENABLE"
}'
action aceita ENABLE ou DISABLE. Resposta (202 Accepted): lista de adIds que serão
processados em segundo plano.
Ligar uma opção não copia o valor atual do produto. Para isso, o painel chama em seguida
POST /bffweb/ads/sync com {"adIds": [...], "eventOptions": [...]}, que reemite os eventos do
produto para esses anúncios.
EANs do anúncio¶
O anúncio tem os mesmos dois campos da variação do produto: eans, a lista de
itens { "value", "main" } (até 20, exatamente um principal), e ean,
depreciado e sem data de remoção, que devolve o EAN principal.
{
"ean": "7891234567890",
"eans": [
{ "value": "7891234567890", "main": true },
{ "value": "17891234567897", "main": false }
]
}
Origem da lista. O anúncio criado a partir do produto copia a lista da
variação. Depois disso, a lista só acompanha o produto se o anúncio tem EAN
em updateOptions; sem a opção, a lista é do anúncio.
Leitura. As respostas de anúncio (GET /integration/ads/full/{id},
GET /integration/ads/list/byOriginSkuId e as consultas de /bffweb/ads)
trazem ean e eans. eans é omitido quando nulo e vem [] quando a
lista está vazia.
Escrita. Criar (POST /bffweb/ads), atualizar (PUT /bffweb/ads/{id}) e
editar em lote (PUT /bffweb/ads/bulk-edit) seguem as mesmas regras do
produto, descritas em
Lista de EANs:
eaneeansausentes ounull: os EANs do anúncio não são alterados.- Só
eancom valor: vira o principal e os secundários são mantidos. - Só
ean: "": remove todos. - Só
eans: a lista enviada substitui a gravada;eans: []remove todos. Com a gravação da lista desabilitada,eanssozinho é ignorado no anúncio, inclusiveeans: []: nada muda. eancom valor eeans, em anúncio que já existe: cada campo é comparado com o gravado.- Lista igual à gravada: vale o
ean(se mudou, vira o principal; a lista é o eco do que foi lido e não é validada). - Lista diferente da gravada: vale a lista, e o par tem de ser coerente —
eanestá emeanse, se há item commain: true, é ele. Senão,400.
- Lista igual à gravada: vale o
ean: ""(vazio ou só com espaços) eeans, em anúncio que já existe:eans: []ou lista igual à gravada: remove todos os EANs. É o caso de quem lê o anúncio, esvaziaeane devolve o corpo.- Lista com itens e diferente da gravada:
400(EAN_NOT_MAIN_OF_EANS), sem gravar nada. - Com a gravação da lista desabilitada:
eansé ignorado e oean: ""remove todos, qualquer que seja a lista.
ean: ""eeanscom itens, na criação: a lista é gravada.- Valor repetido em
eansnão é erro: os repetidos viram um item só. 400(chave de erroinvalid.ean.list), sem gravar nada: mais de ummain: true(MULTIPLE_MAIN); mais de 20 itens depois de juntar os repetidos (TOO_MANY);eanfora da lista (EAN_NOT_IN_EANS);eanna lista, mas o item marcado é outro, ouean: ""comeanscom itens (EAN_NOT_MAIN_OF_EANS). Os dois últimos, na atualização, só quando a lista difere da gravada.
Trecho do corpo de PUT /bffweb/ads/{id} que acrescenta um secundário, com o
par coerente (ean é o item principal de eans):
{
"ean": "7891234567890",
"eans": [
{ "value": "7891234567890", "main": true },
{ "value": "17891234567897", "main": false },
{ "value": "27891234567894", "main": false }
]
}
Um par coerente pode ser reenviado sem mudar o resultado. Reenviar um par
incoerente que passou porque a lista era a gravada (ean novo + lista lida)
devolve 400 na segunda vez; o EAN gravado pela primeira continua lá.
Reenviar ean: "" com a lista lida devolve 400 (EAN_NOT_MAIN_OF_EANS) na
segunda vez — a lista já difere da gravada, vazia — e os EANs continuam
removidos (com a gravação da lista desabilitada, a repetição é aceita e nada
muda). Para remover de forma que possa ser repetida sem erro, envie só
ean: "".
Envie sempre ean junto com eans
A gravação da lista é habilitada por ambiente. Enquanto não estiver, eans
é ignorado na escrita e só ean é gravado — um corpo só com eans não
grava os EANs enviados. Com os dois campos coerentes o resultado é o
esperado nos dois casos. Diferença para o produto: lá, eans: [] sem
ean ainda limpa em POST e PUT com a lista desabilitada; no anúncio
não limpa em nenhuma operação.
Mudança de comportamento
Em criar, atualizar e editar em lote, ean nulo ou omitido não apaga
mais o EAN do anúncio. ean: "" remove; eans: [] só remove com a
gravação da lista habilitada.
Busca e associação. O filtro ean da busca de anúncios
(POST /bffweb/ads/list/search/{platform}) e a associação de anúncio a produto
por EAN casam com qualquer EAN da lista, principal ou secundário.
Trocar o EAN principal não chega a todo canal: o Mercado Livre não atualiza o
GTIN de um anúncio já publicado e a Amazon só envia o EAN na criação. Já é
assim ao trocar o ean.
Endpoints de anúncio (superfície /integration)¶
Listar anúncios por originSkuId¶
curl -X GET "$GUBEE_API/integration/ads/list/byOriginSkuId?originSkuIds=SKU-DEMO-001,SKU-DEMO-002" \
-H "Authorization: Bearer $JWT"
[
{
"id": "ad#1",
"sellerId": "SELLER123",
"originSkuId": "SKU-DEMO-001",
"platform": "MERCADOLIVRE",
"status": "ACTIVE",
"name": "Tênis Runner Preto 42 - ML",
"ean": "7891234567890",
"eans": [
{ "value": "7891234567890", "main": true },
{ "value": "17891234567897", "main": false }
],
"defaultPrice": { "value": 209.90 }
},
{
"id": "ad#5",
"sellerId": "SELLER123",
"originSkuId": "SKU-DEMO-002",
"platform": "SHOPEE",
"status": "ACTIVE",
"name": "Tênis Runner Preto 43 - SHOPEE"
}
]
Limite de 10 originSkuIds por chamada. Acima disso, retorna
400.
Detalhe completo (com template enriquecido)¶
Retorna AdGroupApiDTO com:
- Título e descrição finais (após aplicação do template).
- Todas as variações do grupo (se o anúncio for pai de variações).
- Preço, estoque, imagens, vídeos, atributos, especificações.
Buscar originSkuIds por critério¶
curl -X POST "$GUBEE_API/integration/ads/search/originSkuIds/MERCADOLIVRE" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"status": "ACTIVE",
"onlySimple": true
}'
Retorna lista de originSkuIds cujos anúncios na plataforma informada casam
com o critério. Útil para sincronização inicial de catálogo.
Mapear adId → originSkuId¶
curl -X POST "$GUBEE_API/integration/ads/map/originSkuIds" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '["ad#1", "ad#2", "ad#999"]'
ad#999foi omitido da resposta porque não existe ou não temoriginSkuId. Esta é a semântica do endpoint: IDs inválidos são silenciosamente descartados.
Expandir adIds pais para filhos¶
curl -X POST "$GUBEE_API/integration/ads/obtain/originSkuIds" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '["ad-parent#1"]'
Retorna Set<String> com todos os originSkuIds das variações filhas. Útil
quando o parceiro recebe um adId pai (que não é publicável individualmente) e
precisa dos itens filhos.
Quando usar endpoint de produto vs anúncio¶
| Cenário | Use |
|---|---|
| Criar/atualizar dados de catálogo (título, descrição, dimensões, EANs) | /integration/products/* |
| Sincronizar preço/estoque "default" do produto | /integration/prices/* e /integration/stocks/* (domínio PRODUCT) |
| Sincronizar preço/estoque por marketplace | /integration/prices/platforms/{itemId} com adId como itemId |
| Ler como o anúncio está publicado (com template aplicado) | /integration/ads/full/{id} |
| Descobrir quais anúncios existem para um SKU | /integration/ads/list/byOriginSkuId |
| Ligar/desligar replicação de campos (imagens, vídeos, marca, fiscal, garantia…) | /bffweb/ads/update/updateOptions |
| Atualizar título/descrição específicos do anúncio | /integration/ads/titledescription/byOriginSkuId/{skuId} |
itemId: skuId vs adId¶
Em endpoints que aceitam {itemId} (preço, estoque), o significado depende do
domínio:
domainType=PRODUCT(default):itemIdé oskuIdda variação.domainType=AD:itemIdé oadId.
# preço de um produto (default)
curl -X GET "$GUBEE_API/integration/prices/MERCADOLIVRE/SKUID-123" \
-H "Authorization: Bearer $JWT"
# preço de um anúncio específico
curl -X PUT "$GUBEE_API/integration/prices/platforms/ad%231?domainType=AD" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '[{ "platform": "MERCADOLIVRE", "value": 219.90, "priceType": "DEFAULT" }]'
Consistência entre produto e anúncio¶
Após atualizar preço/estoque no produto, a propagação para os anúncios
derivados acontece via plataforma de streaming de eventos e pode levar até 30s (e mais se a replicação
estiver com updateOptions desativada — nesse caso, o anúncio mantém valor
próprio). Veja CQRS e consistência eventual.
Anúncios são derivados do produto por um job interno; não tente criar anúncios manualmente para refletir uma mudança de produto. A criação de anúncio é um fluxo de publicação separado (normalmente via painel web).
Resumo¶
- Produto = catálogo, fonte da verdade, identificado por
productId/sku/skuId. - Anúncio = publicação em marketplace, identificado por
adId, ligado ao produto viaoriginSkuId. - Preço/estoque podem estar em qualquer dos dois domínios — escolha pelo
domainTypeou pelo endpoint (/prices/byskuvs/prices/platforms/{itemId}). - Replicação é controlada por
updateOptions(TITLE…VIDEOS,BRAND,FISCAL,WARRANTY,CONDITION). - Latência entre produto e anúncio é medida em segundos, não milissegundos.
Próximos passos¶
-
Compatibilidade veicular: consulte veículos e gerencie aplicações de autopeças por anúncio.
-
SKU vs SkuId: identificadores de variação de produto.
- Plataformas: todos os marketplaces suportados.
- Quickstart: crie o produto base antes de tocar anúncios.