OTL ShoesAPI
Exemplos em
Menu da documentação

Pausar o anúncio quando o estoque zera

A OTL avisa o seu sistema quando o estoque de um par muda, e ele pausa (ou reativa) o anúncio no marketplace — sem ninguém olhar planilha.

A ideia

Vender um par que acabou é a pior venda: cancelamento, reclamação e nota baixa no marketplace. Este guia liga o estoque da OTL aos seus anúncios:

  1. Um webhook recebe o aviso produto.estoque_atualizado.
  2. O seu sistema olha o estoque de cada numeração e pausa ou reativa a variação do anúncio.
  3. Uma sincronização periódica cobre o que o webhook perder.

Permissão da integração: produtos:ler.

1. Cadastre o webhook

No painel, em Integrações → Webhooks, cadastre o endereço do seu sistema (ou do n8n) e marque:

  • produto.estoque_atualizado — o estoque de alguma numeração mudou;
  • produto.desativado e produto.reativado — o produto saiu ou voltou ao catálogo.

Em De quais produtos, escolha “só o que a minha loja vende” ou informe a lista de SKUs dos seus anúncios. Assim você não recebe aviso de produto que não anuncia.

2. Trate o aviso — nos dois formatos

O mesmo evento chega de duas formas, e o seu sistema precisa tratar as duas:

  • avulso, quando um produto muda: evento: "produto.estoque_atualizado", com o produto em dados.produto;
  • em lote, quando vários mudam de uma vez (uma carga de estoque): evento: "produto.lote", com a lista em dados.itens, cada item com o próprio evento e produto.
Quem ignora o lote perde justamente as cargas

A carga de estoque é o momento em que mais pares zeram. Se o seu sistema só trata o evento avulso, ele funciona no teste e falha no dia em que mais importa.

// Depois de conferir a assinatura (veja "Conferir a assinatura").
function aoReceber(aviso) {
  const mudancas =
    aviso.evento === 'produto.lote'
      ? aviso.dados.itens // cada item: { evento, produto, ... }
      : [{ evento: aviso.evento, ...aviso.dados }];

  for (const mudanca of mudancas) {
    if (mudanca.evento === 'produto.desativado') pausarTodasAsVariacoes(mudanca.produto.sku);
    else aplicarEstoque(mudanca.produto);
  }
}

function aplicarEstoque(produto) {
  for (const n of produto.numeracoes) {
    // `estoque: null` = a OTL não sabe afirmar. Não é zero: não pause por isso.
    if (n.estoque === null) continue;

    if (n.estoque === 0) pausarVariacao(produto.sku, n.numeracao);
    else reativarVariacao(produto.sku, n.numeracao, n.estoque);
  }
}

O que o corpo traz, e por que isso simplifica o seu código:

  • O estado completo, não a diferença. dados.produto.numeracoes tem o estoque de todas as numerações, não só da que mudou. Você aplica o que chegou, sem precisar saber o que havia antes.
  • Responda rápido. Devolva 200 assim que conferir a assinatura e guardar o aviso; faça as chamadas ao marketplace depois, numa fila. A OTL espera 10 segundos e, sem resposta, tenta de novo.
  • O mesmo aviso pode chegar duas vezes. Deduplique pelo cabeçalho X-OTL-Evento-Id.
  • A ordem não é garantida. Uma nova tentativa de um aviso antigo pode chegar depois de um mais novo. Compare produto.atualizadoEm com o que você já aplicou, e ignore o mais velho.

3. Quanto anunciar

O estoque da OTL é compartilhado entre todos os parceiros e não é reservado para ninguém. Anunciar a quantidade exata é pedir para vender o mesmo par duas vezes. Duas regras práticas:

  • Deixe uma folga. Com 1 ou 2 pares no estoque da OTL, muita gente prefere já pausar a variação.
  • Não anuncie mais do que há. Se a OTL tem 4, anunciar 10 é vender sem ter.
const FOLGA = 1;
const quantidadeNoAnuncio = estoque => Math.max(0, estoque - FOLGA);

Mesmo com tudo isso, a conferência que vale é a da criação do pedido — veja Da venda ao pedido.

4. A rede de segurança

Webhook é aviso, não garantia: o seu endereço pode ficar fora do ar, e depois de várias tentativas a entrega é abandonada. Por isso, a cada 15 a 30 minutos, peça o que mudou:

curl "https://api.otlshoes.com.br/v1/produtos?atualizadoDesde=2026-09-29T14%3A00%3A00-03%3A00&limite=100" \
  -H "Authorization: Bearer otl_prod_SEU_TOKEN"
curl "https://api-sandbox.otlshoes.com.br/v1/produtos?atualizadoDesde=2026-09-29T14%3A00%3A00-03%3A00&limite=100" \
  -H "Authorization: Bearer otl_sbx_SEU_TOKEN"
const resposta = await fetch('https://api.otlshoes.com.br/v1/produtos?atualizadoDesde=2026-09-29T14%3A00%3A00-03%3A00&limite=100', {
  headers: {
    Authorization: 'Bearer otl_prod_SEU_TOKEN',
  },
});

if (!resposta.ok) {
  const { erro } = await resposta.json();
  throw new Error(`${erro.codigo}: ${erro.mensagem} (${erro.requestId})`);
}
const dados = await resposta.json();
const resposta = await fetch('https://api-sandbox.otlshoes.com.br/v1/produtos?atualizadoDesde=2026-09-29T14%3A00%3A00-03%3A00&limite=100', {
  headers: {
    Authorization: 'Bearer otl_sbx_SEU_TOKEN',
  },
});

if (!resposta.ok) {
  const { erro } = await resposta.json();
  throw new Error(`${erro.codigo}: ${erro.mensagem} (${erro.requestId})`);
}
const dados = await resposta.json();
<?php
$ch = curl_init('https://api.otlshoes.com.br/v1/produtos?atualizadoDesde=2026-09-29T14%3A00%3A00-03%3A00&limite=100');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer otl_prod_SEU_TOKEN',
]);

$corpo = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new Exception($corpo['erro']['codigo'] . ': ' . $corpo['erro']['mensagem']);
}
<?php
$ch = curl_init('https://api-sandbox.otlshoes.com.br/v1/produtos?atualizadoDesde=2026-09-29T14%3A00%3A00-03%3A00&limite=100');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer otl_sbx_SEU_TOKEN',
]);

$corpo = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new Exception($corpo['erro']['codigo'] . ': ' . $corpo['erro']['mensagem']);
}
import requests

resposta = requests.get(
    "https://api.otlshoes.com.br/v1/produtos",
    headers={
        "Authorization": "Bearer otl_prod_SEU_TOKEN",
    },
    params={
        "atualizadoDesde": "2026-09-29T14:00:00-03:00",
        "limite": 100
    },
    timeout=30,
)

if not resposta.ok:
    erro = resposta.json()["erro"]
    raise RuntimeError(f'{erro["codigo"]}: {erro["mensagem"]} ({erro["requestId"]})')
dados = resposta.json()
import requests

resposta = requests.get(
    "https://api-sandbox.otlshoes.com.br/v1/produtos",
    headers={
        "Authorization": "Bearer otl_sbx_SEU_TOKEN",
    },
    params={
        "atualizadoDesde": "2026-09-29T14:00:00-03:00",
        "limite": 100
    },
    timeout=30,
)

if not resposta.ok:
    erro = resposta.json()["erro"]
    raise RuntimeError(f'{erro["codigo"]}: {erro["mensagem"]} ({erro["requestId"]})')
dados = resposta.json()
Testar agora no ambiente de testes

A chamada é feita de verdade, do seu navegador para a API de testes (https://api-sandbox.otlshoes.com.br/v1). Use um token otl_sbx_…: ele fica só nesta aba, e some ao fechá-la. Token de produção não é aceito aqui.

Aplique o mesmo aplicarEstoque() a cada produto da resposta. Produtos desativados vêm nessa lista com ativo: false — pause os anúncios deles. O passo a passo está em Sincronizar catálogo e estoque.

Com o webhook funcionando, essa rotina quase sempre volta vazia. É o que se espera dela.

No n8n

  1. Webhook (gatilho), método POST, respondendo “Immediately”.
  2. Code: confira a assinatura — o exemplo pronto está em Conferir a assinatura.
  3. Code: transforme o aviso numa lista, tratando o lote:
const aviso = $json.body;
const mudancas = aviso.evento === 'produto.lote' ? aviso.dados.itens : [{ evento: aviso.evento, ...aviso.dados }];

return mudancas.flatMap(m =>
  m.produto.numeracoes
    .filter(n => n.estoque !== null)
    .map(n => ({ json: { sku: m.produto.sku, numeracao: n.numeracao, estoque: n.estoque, pausar: n.estoque === 0 } })),
);
  1. IF pausar → o nó do seu marketplace que pausa ou reativa a variação.

Teste no sandbox

  1. Cadastre o webhook de teste em Integrações → Ambiente de testes → Webhooks.
  2. Zere uma numeração pelo simulador de estoque.
  3. Em cerca de 1 minuto o aviso chega. Mude outra numeração do mesmo produto antes disso e veja que chega um aviso, com o estado final.
  4. O histórico de entregas, no painel, mostra o que o seu endereço respondeu.

Para ver um produto.lote de verdade, basta esperar: o catálogo de teste é atualizado a partir da produção a cada poucos minutos, e quando vários produtos mudam juntos o aviso vem em lote.

Ver também