Catálogo
Produtos
Criar, atualizar, listar e desativar produtos — o caminho para subir um catálogo inteiro.
Todas as páginas▾
Comece aqui
Inteligência artificial
Referência
O catálogo é a razão de existir desta API. Se o seu sistema tem um id próprio para cada produto, comece pela chave externa: ela é o que torna reenviar o catálogo inteiro seguro, sem duplicar nada.
- GET
/v1/productsLista produtos. Filtros:query(nome ou SKU),active=true|false,page,pageSize. - POST
/v1/productsCria um produto.201no sucesso. - GET
/v1/products/{id}Um produto, com imagens, estoque por depósito, categorias e variações. - PATCH
/v1/products/{id}Atualização parcial — só os campos enviados mudam. - DELETE
/v1/products/{id}Apaga o produto sem pedidos; desativa o que já foi vendido. - PUT
/v1/products/external/{source}/{externalId}Cria ou atualiza pelo id do SEU sistema — reenviar nunca duplica. - GET
/v1/products/external/{source}/{externalId}O produto da sua chave, ou404 product_not_found. - PUT
/v1/products/{id}/stockDefine o estoque absoluto de um depósito (produto sem variação). - GET
/v1/categoriesAs categorias da loja — osslugs quecategorySlugsaceita.
Criar um produto
curl -X POST https://api.zankhapi.com.br/v1/products \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Placa de vídeo RTX 4070",
"sku": "GPU-4070",
"regularPriceCents": 349990,
"compareAtPriceCents": 399990,
"shortDescription": "12GB GDDR6X",
"imageUrls": ["https://exemplo.com/rtx4070-frente.jpg", "https://exemplo.com/rtx4070-verso.jpg"],
"categorySlugs": ["placas-de-video"],
"boxWidthCm": 30, "boxHeightCm": 8, "boxLengthCm": 40, "boxWeightKg": 1.4,
"stockQuantity": 5
}'Campos do produto
| Campo | Tipo | Descrição |
|---|---|---|
nameobrigatório | string | O nome do produto. |
regularPriceCentsobrigatório | integer | Preço de venda em centavos. |
slug | string | O endereço do produto na vitrine. Gerado a partir do nome quando omitido. É único na rede inteira (o marketplace acha o produto só pelo slug): um já usado, mesmo por outra loja, é gravado com um sufixo curto — leia o slug de volta na resposta. |
sku | string | O seu código interno. É por ele que a sua próxima importação reencontra o item. |
shortDescription | string | Uma linha, mostrada nas listagens. |
longDescriptionHtml | string | A descrição completa da página do produto. |
compareAtPriceCents | integer | O preço “de”, riscado. Envie null num PATCH para encerrar a promoção. |
storeInstallmentPriceCents | integer | Preço parcelado exibido. Não altera o que é cobrado no checkout. |
imageUrls | string[] | Até 12 fotos, na ordem da galeria. Copiadas para a zankh — veja Imagens. Substitui a galeria inteira; [] limpa. |
imageUrl | string | Legado: uma foto só. Envie imageUrl ou imageUrls, nunca os dois. Numa atualização troca só a foto principal. |
categorySlugs | string[] | Até 20 slugs de categorias da loja. Substitui as categorias do produto. |
gtin | string | Código de barras (EAN/GTIN). |
brand | string | A marca. |
boxWidthCm / boxHeightCm / boxLengthCm / boxWeightKg | number | A caixa de envio — é ela que calcula o frete. |
preparationDays | integer | Dias úteis de preparo antes do despacho (0–90). |
stockQuantity | integer | Estoque inicial. Depois disso use PUT /stock. |
stockLocationName | string | O depósito do estoque. Omitido, usa o padrão da loja. |
isActive | boolean | Se o produto aparece na vitrine. Padrão true. |
isPurchasable | boolean | Se aceita compra. Um produto ativo e não comprável fica visível como vitrine. |
A resposta traz, além do que você enviou: images, stock (os depósitos do PRODUTO — o depósito de uma variação aparece na variação, nunca aqui), totalStock (a soma desses depósitos), `sellableStock` (esses depósitos + o estoque das variações ATIVAS — o número que dá para vender; use este), categories, hasVariants, variationTypes, variants e externalRef.
Imagens
Toda URL de imageUrls (e de imageUrl) é baixada e copiada para o armazenamento da zankh durante a chamada; o produto guarda a URL da zankh, não a sua. Nada é linkado direto do seu servidor.
- A origem só precisa funcionar durante a chamada — uma URL assinada de curta duração (10 minutos bastam) de um bucket privado serve.
- Só
https://na porta padrão; JPEG, PNG ou WebP (conferido pelo conteúdo, não pela extensão); até 10 MB e 10 s cada; no máximo 3 redirecionamentos. Endereço de rede privada é recusado. - Toda foto vira WebP (lado maior de até 1600 px) em
https://img.zankh.com.br/imported/{storeId}/{hash}.webp. Ohashé do arquivo convertido: reenviar a mesma origem baixa de novo, mas cai na mesma URL — nada muda no produto. - Tudo ou nada: se uma foto falha, nada é gravado e a resposta é
422 image_fetch_failedcomindex(base 0),urlereason(invalid_url,blocked_address,too_many_redirects,timeout,http_status,too_large,not_an_imageoudecode_failed— o arquivo parece imagem mas o conteúdo não é legível). - URLs que o produto já mostra (como vieram em
images) e URLs da zankh da SUA loja no formato acima não são baixadas de novo — reordene a galeria reenviando-as na ordem nova. URL da zankh de outra loja é baixada como qualquer outra. - A cópia é síncrona: 12 fotos grandes podem levar ~30 s. Dê a essas chamadas um timeout de 60–90 s.
- No máximo 2 chamadas copiando fotos ao mesmo tempo por loja; a terceira recebe
429 too_many_requests. - Sem o armazenamento disponível a resposta é
503 image_storage_unavailable— chamadas sem foto continuam funcionando.
Categorias
GET /v1/categories lista as categorias da loja: id, slug, name, parentId, additionalParentIds (uma categoria pode ficar também sob outros pais), position, productCount (direto), productCountWithDescendants e isCatchAll. A API nunca cria categoria: um slug que não existe na loja responde 422 unknown_category com os slugs que faltaram. Todo produto continua também em "Todos os produtos" (isCatchAll: true).
Chave externa (upsert)
PUT /v1/products/external/{source}/{externalId} cria ou atualiza o produto que o SEU sistema chama de externalId. Reenviar nunca duplica — use isto no lugar de "procurar pelo SKU e decidir entre POST e PATCH" (SKU não é único na zankh).
curl -X PUT https://api.zankhapi.com.br/v1/products/external/meuerp/sku-985561 \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Gato articulado",
"regularPriceCents": 6990,
"imageUrls": ["https://arquivos.exemplo.com/assinada/gato-1.png?sig=..."],
"categorySlugs": ["animais-e-esculturas"],
"preparationDays": 3
}'sourcenomeia a sua integração (2–32 caracteres: minúsculas, dígitos e-).externalId: 1–128 caracteres entre letras, dígitos,.,_,:e-. A chave é por loja.- O corpo é o de criação (
nameeregularPriceCentssempre obrigatórios) maisadoptProductIdopcional. - Chave nova → cria (
201). Chave existente → atualiza (200): o que veio sobrescreve,nulllimpa, o ausente fica. Na atualização,slugé ignorado (renomear URL publicada quebra link e SEO) e umisActiveausente mantém o que a loja decidiu. - `adoptProductId` (migração, uma vez só): liga a chave nova a um produto que já existe em vez de criar outro. O produto precisa ser seu (
404) e não ter outra chave (409 external_ref_conflict) — nem ter sido importado de um marketplace (Shopee, Mercado Livre...), que é quem o mantém sincronizado: um produto tem um dono só. stockQuantitynum produto com variação ativa responde409 product_has_variants.- Mudar o preço do produto também move as variações que estavam exatamente no preço antigo — a zankh trata essas como herdeiras dele; variação com preço próprio fica. Se você controla preço por variação, envie o produto primeiro e as variações depois: aquela chamada é absoluta e tem a última palavra.
Atualizar
PATCH é parcial: o que você não enviar fica como está. É o que permite um script de preço mexer só em preço, sem arrastar a descrição junto.
curl -X PATCH https://api.zankhapi.com.br/v1/products/PRODUTO_ID \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-d '{ "regularPriceCents": 329990, "compareAtPriceCents": null }'Apagar ou desativar
DELETE apaga de verdade um produto que nunca foi vendido (resposta { id, deleted: true }) e desativa o que já está em algum pedido ({ id, deleted: false, isActive: false }): ele sai da vitrine e continua existindo para os pedidos que o referenciam. Um pedido do mês passado não pode ficar sem saber o que foi vendido.
Subir um catálogo inteiro
- Envie cada produto com
PUT /v1/products/external/{source}/{seuId}— cria o que falta e atualiza o que já existe, um por chamada (não há rota em lote no v1). - Produtos criados antes da chave: case pelo
sku(GET /v1/products?pageSize=200) e mandeadoptProductIduma vez. - Depois do produto, as variações dele, se houver.
409 slug_takensó aparece quando duas chamadas disputam o mesmo slug livre no mesmo instante — repita a chamada.