Pular para o conteúdo
MeWeb

Desenvolvedores

Webhooks

Um webhook é o caminho inverso da chave de API: em vez de o seu sistema perguntar de tempos em tempos se algo mudou, a loja avisa assim que o fato acontece. Cada entrega é um POST assinado com HMAC-SHA256 para o endereço HTTPS cadastrado pelo lojista.

Cadastrando

Quem cadastra é o lojista, no admin da loja: Configurações → Webhooks → Novo webhook. Ele informa a URL, escolhe os eventos e recebe o segredo de assinatura whsec_… uma única vez; combine um canal seguro para recebê-lo. São até 10 endpoints por loja, e o recurso exige um plano com acesso à API.

A URL precisa ser https e resolver para um endereço público: endereços de rede interna são recusados no cadastro e revalidados a cada entrega. Redirecionamentos não são seguidos; aponte direto para o destino final.

O que chega

requisição
POST /seu-endpoint HTTP/1.1
Content-Type: application/json
X-MeWeb-Event: OrderPaid
X-MeWeb-Delivery: 01J8ZQ3M4K5N6P7Q8R9S0T1U2V
X-MeWeb-Signature: t=1770000000,v1=5257a869e7ec...

{
  "id": "01J8ZQ3M4K5N6P7Q8R9S0T1U2V",
  "type": "OrderPaid",
  "v": 1,
  "occurredAt": "2026-08-08T12:00:00.000Z",
  "data": {
    "orderId": "01J8ZQ3M4K5N6P7Q8R9S0T1U2V",
    "number": 1042,
    "customerId": "01J8ZQ3M4K5N6P7Q8R9S0T1U30",
    "totalCents": 13300,
    "items": [
      { "quantity": 2, "totalCents": 9800 },
      { "quantity": 1, "totalCents": 3500 }
    ]
  }
}

O campo data traz os identificadores e os fatos imutáveis do evento, nunca a entidade inteira. Para o detalhe completo, busque o recurso pela API Admin com a sua chave. Assim o payload não envelhece nem vaza mais do que o necessário.

Payload mínimo e dados pessoais

Existem dois modos, escolhidos pelo lojista em cada endpoint:

  • Payload mínimo (padrão): o data leva apenas identificadores (orderId, customerId, productId, sku, número do pedido), status, valores em centavos, quantidades, datas e código de rastreio. Nome, e-mail, telefone, endereço e qualquer texto livre (inclusive o título dos itens) não são enviados.
  • Com dados pessoais: o lojista marca “Incluir dados pessoais do cliente no payload” no cadastro do endpoint e passa a receber também esses campos. É opt-in por endpoint, e a responsabilidade pelos dados no destino é dele (LGPD).
data: com dados pessoais
"data": {
  "orderId": "01J8ZQ3M4K5N6P7Q8R9S0T1U2V",
  "number": 1042,
  "customerId": "01J8ZQ3M4K5N6P7Q8R9S0T1U30",
  "email": "cliente@exemplo.com",
  "customerName": "Maria Silva",
  "totalCents": 13300,
  "items": [
    { "title": "Camiseta P", "quantity": 2, "totalCents": 9800 },
    { "title": "Caneca", "quantity": 1, "totalCents": 3500 }
  ]
}

Escreva o consumidor para o payload mínimo. Ele é o padrão de todo endpoint novo, e é o que você recebe se o lojista desligar a opção depois. Precisa do nome ou do e-mail do comprador? Busque o pedido pela API Admin usando o orderId que chegou; o dado vem sempre atualizado e você não guarda uma cópia que precisa manter em dia.

Trate o campo ausente como normal, não como erro: um campo fora da lista acima simplesmente não aparece no objeto. Endpoints cadastrados antes de 22/08/2026 continuam recebendo o payload completo até o lojista desligar a opção.

Verificando a assinatura

O header X-MeWeb-Signature tem o formato t=<unix>,v1=<hmac>, onde v1 é o HMAC-SHA256 de "<t>.<corpo cru>" usando o segredo do endpoint. Sempre verifique antes de processar: sem isso, qualquer um que descubra a sua URL pode forjar um pedido pago.

Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';

const TOLERANCE_SECONDS = 300; // 5 minutos

export function verificar(corpoCru, header, segredo) {
  const partes = Object.fromEntries(
    header.split(',').map((p) => {
      const [k, ...resto] = p.trim().split('=');
      return [k, resto.join('=')];
    }),
  );
  const t = Number(partes.t);
  if (!Number.isFinite(t) || !partes.v1) return false;

  // Recusa entregas antigas (anti-replay)
  const agora = Math.floor(Date.now() / 1000);
  if (Math.abs(agora - t) > TOLERANCE_SECONDS) return false;

  const esperado = createHmac('sha256', segredo)
    .update(`${t}.${corpoCru}`)
    .digest('hex');

  const a = Buffer.from(esperado, 'utf8');
  const b = Buffer.from(partes.v1, 'utf8');
  return a.length === b.length && timingSafeEqual(a, b);
}

Recebendo com segurança

Express
import express from 'express';

const app = express();

// IMPORTANTE: a assinatura cobre o corpo CRU. Se o JSON for
// interpretado antes, a re-serialização muda os bytes e a
// verificação falha: use express.raw() nesta rota.
app.post('/meweb', express.raw({ type: 'application/json' }), (req, res) => {
  const corpoCru = req.body.toString('utf8');
  if (!verificar(corpoCru, req.get('X-MeWeb-Signature'), process.env.MEWEB_WEBHOOK_SECRET)) {
    return res.sendStatus(401);
  }

  const evento = JSON.parse(corpoCru);

  // Deduplicação: a mesma entrega pode chegar mais de uma vez.
  if (jaProcessamos(req.get('X-MeWeb-Delivery'))) return res.sendStatus(200);

  // Responda 2xx RÁPIDO e processe depois: o MeWeb desiste em 10 s.
  enfileirar(evento);
  res.sendStatus(200);
});

Novas tentativas e duplicatas

  • Sucesso é qualquer 2xx, respondido em até 10 segundos. Responda primeiro e processe depois: trabalho pesado dentro da requisição vira timeout, e timeout vira nova tentativa.
  • Falhou? São até 5 tentativas, esperando 1 min, 5 min, 30 min e 2 h entre elas. Depois disso a entrega fica marcada como falha e o lojista pode reenviá-la à mão pelo painel.
  • Entrega ao menos uma vez: a mesma ocorrência pode chegar em duplicidade (uma resposta perdida no caminho, por exemplo). Guarde o X-MeWeb-Delivery já processado e ignore repetições. Um reenvio manual chega com um id novo; deduplique também pelo conteúdo quando a operação não for idempotente.
  • Sem ordem garantida: use o campo occurredAt para ordenar, nunca a ordem de chegada.
  • 20 falhas seguidas desativam o endpoint e avisam o lojista por e-mail. Enquanto estiver desativado, nenhum evento é entregue, nem retroativamente ao reativar.

Trocando o segredo

O lojista pode gerar um segredo novo a qualquer momento. A troca vale na hora: o segredo anterior para de assinar imediatamente, então atualize o seu lado antes, ou as entregas seguintes serão recusadas pela sua própria verificação.

Testando

O botão Enviar teste no painel dispara um evento ping e mostra na hora o código que o seu endereço respondeu: é a forma mais rápida de conferir a assinatura e o roteamento antes de depender de um pedido de verdade. O painel também lista todas as entregas dos últimos 30 dias com status, tentativas e o código devolvido.