Introdução
A API pública v1 permite que sistemas externos integrem com sua loja. Use-a para sincronizar produtos com seu ERP, importar pedidos, automatizar movimentações de estoque ou exportar clientes.
Base URL: https://katalog.com.br/api/v1
Autenticação
Todas as requisições devem incluir um Bearer token no header. Crie tokens no painel em /painel/api-tokens.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO token está vinculado a uma loja específica. Não compartilhe seu token publicamente. Se for comprometido, revogue-o no painel e gere um novo.
Formato de resposta
Todas as respostas são JSON. Em caso de erro:
{
"erro": "Mensagem descritiva do erro"
}Códigos HTTP usados:
200— sucesso201— recurso criado400— erro de validação401— token inválido ou ausente404— recurso não encontrado500— erro interno
Produtos
GET /produtos — Listar produtos
Query params:
busca— filtra por nome, código de barras, SKU oucodIntegracao(quando numérico)categoriaId— filtra por categoriaapenasDisponiveis—truepara esconder os indisponíveispage,limite— paginação (default 1, 50)
Cada item da lista retorna também codIntegracao (Código ERP — inteiro identificador no sistema externo, ex.: Integreon) e as variações trazem o própriocodIntegracao.
URL pública: o campo url traz o link absoluto do produto no storefront (mesma URL do canonical/og:url) — formato https://{slug}.katalog.com.br/produto/{id} ou o domínio personalizado da loja quando configurado. Devolvido em GET /produtos, GET /produtos/[id], POST /produtos e PUT /produtos/[id].
curlcurl https://katalog.com.br/api/v1/produtos?limite=10 \ -H "Authorization: Bearer sk_live_..."
GET /produtos/[id] — Detalhes
curlcurl https://katalog.com.br/api/v1/produtos/PRODUTO_ID \ -H "Authorization: Bearer sk_live_..."
POST /produtos — Criar produto
Aceita codIntegracao (inteiro) para vincular o registro ao ID do produto no sistema externo (Integreon, ERP, etc). Se categoriaId não for enviado, o produto cai automaticamente em uma categoria "Sem categoria" criada na loja (uma única vez). Isso evita ter que fazer GET /categorias antes de cada importação.
Aceita também unidade (máx 10 chars, ex: UN, KG, L, M, PC; normalizado para maiúsculas; default PC) e multiploVenda (decimal > 0, default 1; ex: 10 para fardo de 10). Ambos podem ser editados depois via PUT.
Imagens externas: se você enviar imagens: ["https://outro-dominio/..."], baixamos cada URL e re-hospedamos no nosso S3 antes de gravar. Sem isso, o catálogo público bloqueia o domínio externo no <Image> do Next e mostra um quadrado vazio. URLs que já estão no nosso S3/CloudFront passam intactas.
curlcurl -X POST https://katalog.com.br/api/v1/produtos \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "nome": "Camiseta Branca", "preco": 49.90, "descricao": "100% algodão", "codigoBarras": "7891234567890", "sku": "CAM-BR-M", "codIntegracao": 1234, "controlaEstoque": true, "quantidadeEstoque": 100 }'
PUT /produtos/[id] — Atualizar
Atualiza campos parciais (envie só os que mudaram). Dispara o webhook produto.atualizado. Aceita:
nome,descricao,preco,precoPromocionalcategoriaId(validado: precisa pertencer à loja)imagens(array de URLs),sku,codigoBarrascodIntegracao— Código ERP (inteiro). Envienullpara limpardisponivel,destaque,ordemcontrolaEstoque,quantidadeEstoque,estoqueMinimopeso(kg),altura,largura,comprimento(cm) — para frete em marketplaces
curlcurl -X PUT https://katalog.com.br/api/v1/produtos/PRODUTO_ID \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "preco": 59.90, "quantidadeEstoque": 80, "peso": 0.250, "altura": 5, "largura": 30, "comprimento": 40 }'
Resposta 200: produto completo (mesmo formato do GET).
DELETE /produtos/[id] — Remover
Soft-delete: marca o produto como removido (deletadoEm = now() e disponivel = false). O produto somem dos GET da API mas permanece no histórico de pedidos. Idempotente — retorna 404 se já foi removido. Dispara o webhook produto.removido.
curlcurl -X DELETE https://katalog.com.br/api/v1/produtos/PRODUTO_ID \ -H "Authorization: Bearer sk_live_..."
{ "id": "PRODUTO_ID", "removido": true }Variações
Variações são as combinações de atributos de um produto (ex.: tamanho/cor). Cada variação tem seu próprio preço, estoque, SKU, código de barras e codIntegracao.
GET /produtos/[id]/variacoes — Listar variações do produto
curlcurl https://katalog.com.br/api/v1/produtos/PRODUTO_ID/variacoes \ -H "Authorization: Bearer sk_live_..."
POST /produtos/[id]/variacoes — Criar variação
curlcurl -X POST https://katalog.com.br/api/v1/produtos/PRODUTO_ID/variacoes \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "nome": "Tamanho M", "valor1": "M", "valor2": "Branco", "preco": 49.90, "sku": "CAM-BR-M", "codigoBarras": "7891234567891", "codIntegracao": 5678, "quantidadeEstoque": 30 }'
GET /variacoes/[id] — Detalhes
PUT /variacoes/[id] — Atualizar
Aceita os mesmos campos do POST (todos opcionais). Envie codIntegracao: nullpara limpar.
curlcurl -X PUT https://katalog.com.br/api/v1/variacoes/VARIACAO_ID \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "preco": 54.90, "codIntegracao": 9999 }'
DELETE /variacoes/[id] — Remover
Remoção definitiva (hard delete). Não há soft-delete para variações.
Complementos (Grupos)
Grupos de complemento são reutilizáveis (um mesmo grupo "Sabores" pode ser vinculado a vários produtos). Os itens do grupo são armazenados como JSON e cada item aceita nome, preco, estoque e codIntegracao.
GET /grupos-complemento — Listar grupos
curlcurl https://katalog.com.br/api/v1/grupos-complemento \ -H "Authorization: Bearer sk_live_..."
POST /grupos-complemento — Criar grupo
curlcurl -X POST https://katalog.com.br/api/v1/grupos-complemento \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "nome": "Sabores", "tipo": "SELECAO", "obrigatoria": true, "minimo": 1, "maximo": 1, "itens": [ { "nome": "Chocolate", "preco": 0, "codIntegracao": 11 }, { "nome": "Morango", "preco": 0, "codIntegracao": 12 }, { "nome": "Baunilha", "preco": 0, "codIntegracao": 13 } ] }'
Campos do body:
tipo—SELECAO(1 opção) ouMULTIPLA(várias)obrigatoria,minimo,maximo— regras de seleçãoitens— array de objetos{ nome, preco, estoque?, codIntegracao? }. OcodIntegracaodentro do item é o Código ERP daquele complemento.
GET /grupos-complemento/[id]
PUT /grupos-complemento/[id] — Atualizar
Se itens estiver presente, substitui completamente a lista anterior (não faz merge item-a-item). Reenvie a lista completa, com oscodIntegracao atualizados.
DELETE /grupos-complemento/[id] — Remover
Categorias
GET /categorias — Listar
Lista todas as categorias da loja.
POST /categorias — Criar
Cria categoria. nome é único por loja (case-insensitive). ordem é opcional — quando omitido, vai pro fim. Hierarquia Categoria → Subcategoria existe no schema mas é tratada em endpoint separado; categoriaPaiId no body é ignorado.
curlcurl -X POST https://katalog.com.br/api/v1/categorias \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "nome": "Hambúrgueres", "ordem": 1, "ativa": true }'
GET /categorias/[id] — Detalhes
PUT /categorias/[id] — Atualizar
Body (todos opcionais): nome, descricao, ordem, ativa. Renomear pra nome já usado por outra categoria retorna 400.
DELETE /categorias/[id] — Remover
Bloqueia (409) se a categoria tiver produtos ou subcategorias vinculados — sem isso, a cascata onDelete: Cascade apagaria os produtos junto. Realoque os produtos via PUT /produtos/[id] com novo categoriaId antes.
curlcurl -X DELETE https://katalog.com.br/api/v1/categorias/CAT_ID \ -H "Authorization: Bearer sk_live_..."
# 409 Conflict quando tem dependencia:
{ "erro": "Categoria tem 12 produto(s) vinculado(s). Realoque-os antes de remover.",
"produtosVinculados": 12 }Upsert de categoria no POST /produtos
Pra evitar 2 chamadas (criar categoria + criar produto), o POST /produtos aceita categoria (string) em vez de categoriaId. Se a categoria já existe (match case-insensitive), reusa; se não, cria. Ordem de prioridade no resolve:
categoriaIdexplícito (valida pertencimento à loja)categoria(string) → upsert por nome- Nenhum → cai em "Sem categoria" automática
curlcurl -X POST https://katalog.com.br/api/v1/produtos \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "nome": "X-Bacon", "preco": 28.90, "categoria": "Hambúrgueres" }'
Clientes
GET /clientes
Query params: busca, page, limite.
POST /clientes
Cria ou atualiza (upsert por documento). Campos:
{
"nome": "João da Silva",
"documento": "12345678900",
"tipoDocumento": "CPF",
"email": "joao@example.com",
"celular": "11999999999",
"cep": "01310100",
"endereco": "Av. Paulista",
"numero": "1000",
"bairro": "Bela Vista",
"cidade": "São Paulo",
"uf": "SP"
}Pedidos
GET /pedidos
Query params:
status— PENDENTE, CONFIRMADO, PREPARANDO, PRONTO, ENTREGUE, CANCELADOdesde— ISO date (filtro de criação >=)ate— ISO date (filtro de criação <=)page,limite
curlcurl "https://katalog.com.br/api/v1/pedidos?status=ENTREGUE&desde=2026-01-01" \ -H "Authorization: Bearer sk_live_..."
POST /pedidos — Criar pedido
Cria um pedido na loja. Preço é recalculado server-side (variação > promo > preço base) — o valor enviado no body é ignorado por segurança. Estoque é baixado em transação atômica: se um item não tem estoque, retorna 400 e nenhum item é baixado.
tipoEntrega—DELIVERY,BALCAO(retirada no balcão;RETIRADAtambém é aceito como alias) ouMESAcliente— objeto com snapshot. Secliente.idfor passado, valida que pertence à loja e usa o cadastro como fallback nos campos vaziositens[]— cada um comprodutoId,quantidade, opcionalvariacaoId,observacaoeopcoes(JSON de complementos)taxaEntrega,desconto,observacoes— opcionais
Dispara webhook pedido.criado ao sucesso. Não suporta cupons, cashback, mesas, múltiplas formas de pagamento, frete dinâmico, tabela de preço — use o painel pra esses fluxos.
Atenção ao múltiplo de venda: produtos com multiploVenda > 1 (ex: parafuso vendido de 10 em 10) têm a quantidade arredondada automaticamente para o próximo múltiplo. Pedir quantidade: 1 de um produto com multiploVenda: 10 grava 10 no pedido. Cheque esse campo no GET /produtos antes de enviar.
curlcurl -X POST https://katalog.com.br/api/v1/pedidos \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "tipoEntrega": "DELIVERY", "cliente": { "nome": "João da Silva", "celular": "11999999999", "email": "joao@example.com", "documento": "12345678900", "endereco": "Av. Paulista", "numero": "1000", "bairro": "Bela Vista", "cidade": "São Paulo", "uf": "SP", "cep": "01310100" }, "itens": [ { "produtoId": "PROD_ABC", "quantidade": 2 }, { "produtoId": "PROD_XYZ", "variacaoId": "VAR_123", "quantidade": 1, "observacao": "sem cebola" } ], "taxaEntrega": 8.50, "observacoes": "Entregar após 18h" }'
GET /pedidos/[id] — Detalhes
Retorna o pedido completo com itens, cliente e dados de rastreio.
PATCH /pedidos/[id] — Atualizar status / rastreio
Body (todos os campos exceto status são opcionais):
status—PENDENTE,CONFIRMADO,PREPARANDO,PRONTO,ENVIADO,ENTREGUEouCANCELADOmotivoCancelamento— obrigatório quandostatus = CANCELADOtempoEntrega— string livre (ex:"30-45 min")codigoRastreio,urlRastreio— para marketplaces / Correios
Comportamento automático:
- Ao mudar
PENDENTE → CONFIRMADO: baixa estoque dos itens - Ao cancelar pedido confirmado: restaura estoque
- Sempre dispara webhook
pedido.status - Se
status = CANCELADO: também disparapedido.cancelado
curlcurl -X PATCH https://katalog.com.br/api/v1/pedidos/PEDIDO_ID \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "status": "ENVIADO", "codigoRastreio": "BR123456789", "urlRastreio": "https://rastreamento.correios.com.br/...", "tempoEntrega": "3-5 dias úteis" }'
Estoque
POST /estoque — Movimentação
Registra movimentação de estoque (entrada, saída ou ajuste).
{
"produtoId": "PRODUTO_ID",
"tipo": "ENTRADA", // ou "SAIDA" ou "AJUSTE"
"quantidade": 50,
"variacaoId": null, // opcional
"observacao": "Compra do fornecedor X"
}- ENTRADA: soma à quantidade atual
- SAIDA: subtrai da quantidade atual
- AJUSTE: define a quantidade absoluta
Exemplo: importar produtos do ERP
javascriptconst TOKEN = "sk_live_..."; const BASE = "https://katalog.com.br/api/v1"; async function criarProduto(produto) { const res = await fetch(`${BASE}/produtos`, { method: "POST", headers: { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(produto), }); if (!res.ok) { const err = await res.json(); throw new Error(err.erro); } return res.json(); } // Loop sobre os produtos do ERP for (const item of produtosDoERP) { await criarProduto({ nome: item.descricao, preco: item.precoVenda, codigoBarras: item.ean, sku: item.codigo, controlaEstoque: true, quantidadeEstoque: item.estoqueAtual, }); }
Limites
Limite atual: 60 requisições por minuto por token. Em caso de excesso, retornamos 429 Too Many Requests com os headers:
X-RateLimit-Limit— limite total (60)X-RateLimit-Remaining— quantas restam na janelaX-RateLimit-Reset— segundos até resetarRetry-After— segundos sugeridos antes de tentar de novo
Recursos extras
- SDKs prontos — JavaScript, Python e PHP
- OpenAPI Spec — Swagger UI + Postman
- Status — disponibilidade dos serviços
- Gerenciar tokens — criar, revogar, métricas
Webhooks de saída
Receba notificações em uma URL externa quando eventos ocorrerem na sua loja. Pode configurar pelo painel em /painel/webhooks ou via API (abaixo).
Eventos disponíveis
pedido.criado— novo pedido recebidopedido.status— status do pedido mudoupedido.pago— pagamento confirmadopedido.cancelado— pedido canceladocliente.criado— novo cliente cadastradoproduto.atualizado— produto foi alterado (PUT)produto.removido— produto foi removido (DELETE)produto.estoque_baixo— produto atingiu o mínimo
POST /webhooks — Cadastrar webhook
Cria um webhook scoped à loja autenticada. O secret é gerado pelo servidor (formato whsec_<48 hex>) e retornado apenas neste response — guarde-o, não há como recuperá-lo depois.
curlcurl -X POST https://katalog.com.br/api/v1/webhooks \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "nome": "Integreon", "url": "https://hub.integreon.com.br/webhooks/meucatalogo", "eventos": ["pedido.criado", "produto.atualizado", "produto.removido"] }'
{
"id": "...",
"nome": "Integreon",
"url": "https://...",
"eventos": ["pedido.criado", "produto.atualizado", "produto.removido"],
"ativo": true,
"secret": "whsec_abc123...",
"criadoEm": "2026-04-27T..."
}GET /webhooks — Listar
Retorna os webhooks da loja (sem expor o secret).
DELETE /webhooks/[id] — Remover
curlcurl -X DELETE https://katalog.com.br/api/v1/webhooks/WEBHOOK_ID \ -H "Authorization: Bearer sk_live_..."
Formato do payload
POST com Content-Type application/json e os headers:
X-MeuCatalogo-Event: pedido.criado
X-MeuCatalogo-Signature: sha256=<hex>
Content-Type: application/jsonBody:
{
"evento": "pedido.criado",
"criadoEm": "2026-04-22T15:30:00Z",
"dados": {
"id": "...",
"numero": 123,
"total": 89.90,
"status": "PENDENTE"
}
}Validar a assinatura HMAC
Use o secret mostrado no momento da criação do webhook. Calcule HMAC SHA-256 do body com o secret e compare com o header X-MeuCatalogo-Signature.
javascriptimport crypto from "crypto"; function verificarAssinatura(secret, body, assinatura) { const hmac = crypto.createHmac("sha256", secret); hmac.update(body); const esperada = "sha256=" + hmac.digest("hex"); return crypto.timingSafeEqual( Buffer.from(esperada), Buffer.from(assinatura) ); }
Retentativas e timeout
Cada entrega tem timeout de 10 segundos. Sua URL deve responder com status 2xx para ser considerada sucesso.
Em caso de falha, retentamos com backoff exponencial: +30s, +2min, +10min, +1h (total de 5 tentativas). O header X-MeuCatalogo-Tentativa indica o número da tentativa.
Logs
Visualize histórico de entregas em /painel/webhooks. Cada log mostra: payload enviado, status HTTP recebido, resposta e duração.
Suporte
Encontrou um bug ou precisa de um endpoint que ainda não existe? Fale com nosso time pelo WhatsApp.