Todos os artigos

Integrações · 25 de julho de 2026 · 12 min de leitura

Webhooks do Mercado Pago e Pix: guia completo de integração e testes

Um Pix é confirmado em segundos — e o seu sistema precisa saber disso na hora, sem ficar consultando a API do Mercado Pago em loop. É para isso que existem os webhooks de notificação. Neste guia, você vai configurar as notificações do zero, validar a assinatura x-signature, montar o fluxo completo de um pagamento Pix e testar tudo antes de ir para produção — incluindo os erros que mais travam integrações reais.

Por que o Mercado Pago notifica via webhook

Quando um cliente paga com Pix, a aprovação acontece em segundos; com cartão, o status pode mudar de in_process para approved ou rejected minutos depois; com boleto, dias depois. Consultar a API a cada poucos segundos para cada pedido em aberto não escala e ainda esbarra em rate limits. O modelo invertido resolve: o Mercado Pago envia um POST para a sua URL sempre que algo relevante acontece, e a sua aplicação reage na hora.

Historicamente existiram dois mecanismos: o IPN (Instant Payment Notification), hoje descontinuado, e os Webhooks, que são o caminho recomendado e o único que você deve usar em integrações novas. Toda a documentação oficial está na página de notificações Webhooks do Mercado Pago. Se você ainda não domina o funcionamento geral de webhooks (retries, idempotência, resposta rápida), vale começar pelo nosso guia O que é um webhook e como funciona.

Configurando as notificações

Pelo painel do desenvolvedor

  1. Acesse Suas integrações, selecione a sua aplicação e abra Webhooks → Configurar notificação.
  2. Cadastre a URL do seu endpoint — obrigatoriamente HTTPS válido e acessível pela internet. Há dois campos separados: modo teste (usado com credenciais de teste) e modo produção.
  3. Selecione os eventos que quer receber. Para pagamentos (Pix, cartão, boleto), o tópico é payment, que dispara as ações payment.created e payment.updated.
  4. Guarde a assinatura secreta exibida nessa tela — é com ela que você vai validar o header x-signature. Ela pode ser regenerada a qualquer momento (e aí é preciso atualizar o seu ambiente).

Via API, por pagamento

Alternativamente (ou em conjunto), você pode informar o campo notification_url ao criar o pagamento ou a preferência de checkout. É útil quando cada loja ou tenant do seu sistema tem um endpoint próprio. A notificação chega no mesmo formato; a diferença é apenas onde a URL foi definida.

O que chega no seu endpoint

A notificação é um POST com o identificador do recurso na query string (data.id e type) e um corpo JSON resumido:

POST /webhooks/mercadopago?data.id=12345678901&type=payment
{
  "id": 987654321,
  "live_mode": true,
  "type": "payment",
  "date_created": "2026-07-25T14:32:07.000-04:00",
  "user_id": 44444,
  "api_version": "v1",
  "action": "payment.updated",
  "data": { "id": "12345678901" }
}

O fluxo completo de um Pix, passo a passo

  1. Você cria o pagamento Pix e exibe o QR code para o cliente.
  2. O cliente paga no app do banco; o Mercado Pago aprova em segundos.
  3. O Mercado Pago envia a notificação (action: payment.updated) para a sua URL, com a assinatura no header x-signature.
  4. Seu endpoint valida a assinatura e responde 200 imediatamente — o Mercado Pago aguarda a resposta por cerca de 22 segundos; sem ela, considera falha e reenvia depois.
  5. Fora do ciclo da resposta, sua aplicação consulta GET /v1/payments/12345678901 com o access token da conta.
  6. Se status = "approved", o pedido é liberado; qualquer outro status apenas atualiza o registro interno.

Em código (Node + Express), o esqueleto do handler fica assim:

handler do webhook — responda rápido, processe depois
app.post("/webhooks/mercadopago", async (req, res) => {
  // 1. Rejeite requisições sem assinatura válida (ver seção abaixo)
  if (!assinaturaValida(req)) return res.sendStatus(401);

  // 2. Confirme o recebimento já — sem esperar o processamento
  res.sendStatus(200);

  // 3. Trabalho pesado vai para uma fila, nunca no ciclo da resposta
  const { type, data } = req.body;
  if (type === "payment") {
    await fila.add("processar-pagamento", { paymentId: data.id });
  }
});
no worker — a API é a fonte de verdade
const resp = await fetch(
  `https://api.mercadopago.com/v1/payments/${paymentId}`,
  { headers: { Authorization: `Bearer ${process.env.MP_ACCESS_TOKEN}` } },
);
const pagamento = await resp.json();

if (pagamento.status === "approved" && pagamento.live_mode) {
  await liberarPedido(pagamento.external_reference);
}

Validando a assinatura x-signature

Seu endpoint é público — qualquer pessoa que descubra a URL pode enviar um POST com um JSON idêntico ao do Mercado Pago. A assinatura é o que separa uma notificação legítima de uma forjada. O header chega neste formato:

headers relevantes
x-signature: ts=1704908010,v1=618c85345248dd820d5fd456117c2ab2ef8eda45...
x-request-id: bb56a2f1-6aae-46ac-982e-9dcd3581d08e

A validação tem quatro passos:

  1. Extraia ts e v1 do header x-signature.
  2. Monte o manifest com o template oficial: id:[data.id];request-id:[x-request-id];ts:[ts]; — usando o data.id da query string e o header x-request-id.
  3. Calcule o HMAC-SHA256 do manifest em hexadecimal, usando a assinatura secreta do painel como chave.
  4. Compare o resultado com v1 usando comparação de tempo constante.
validação da assinatura em Node
import crypto from "node:crypto";

function assinaturaValida(req) {
  const assinatura = req.headers["x-signature"]; // "ts=...,v1=..."
  const requestId = req.headers["x-request-id"];
  const dataId = req.query["data.id"];
  if (!assinatura || !requestId || !dataId) return false;

  const partes = Object.fromEntries(
    assinatura.split(",").map((p) => p.trim().split("=")),
  );
  if (!partes.ts || !partes.v1) return false;

  const manifest = `id:${dataId};request-id:${requestId};ts:${partes.ts};`;

  const esperado = crypto
    .createHmac("sha256", process.env.MP_WEBHOOK_SECRET)
    .update(manifest)
    .digest("hex");

  return (
    esperado.length === partes.v1.length &&
    crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(partes.v1))
  );
}

Eventos que valem a pena assinar

Evento (action)Quando disparaO que fazer
payment.createdPagamento criado: Pix aguardando, boleto emitido, cartão em análiseRegistrar o pagamento e aguardar a atualização
payment.updatedStatus mudou: aprovado, recusado, estornado, canceladoConsultar GET /v1/payments/{id} e atualizar o pedido
chargebacksContestação aberta ou alteradaSuspender a entrega e reunir evidências da venda
subscription_preapprovalAssinatura criada, pausada ou canceladaSincronizar o status da assinatura no seu sistema

Como testar antes de ir para produção

  • Contas de teste. Crie um par vendedor/comprador em "Contas de teste" no painel. O vendedor de teste tem credenciais próprias — é com elas que você cria pagamentos de sandbox e recebe notificações no endpoint de modo teste.
  • Simulador de notificações. Na tela de configuração de Webhooks há um botão de simulação que envia uma notificação de exemplo para a sua URL — o jeito mais rápido de conferir conectividade e validação de assinatura.
  • Inspecione o payload real primeiro. Antes de escrever o handler, aponte a URL de teste para um endpoint de inspeção (uma URL temporária que captura e exibe cada requisição, com headers e body). Ver um x-signature e um corpo reais elimina metade das dúvidas de integração.
  • Desenvolvimento local. O Mercado Pago não alcança localhost — você vai precisar de um túnel ou de encaminhamento de eventos. As opções estão comparadas em Como testar webhooks em localhost.
  • Cartões e pagadores de teste. Use os cartões de teste documentados (aprovação, recusa por saldo, recusa por segurança) para simular cada caminho do seu fluxo, e o Pix de sandbox para o fluxo instantâneo.

Troubleshooting: os problemas clássicos

A notificação nunca chega

Quase sempre é infraestrutura: URL com HTTPS inválido (certificado expirado ou self-signed), firewall/WAF bloqueando o IP do Mercado Pago, ou a URL cadastrada no modo errado (teste × produção). Confirme com o simulador do painel e verifique se o seu endpoint responde em menos de 22 segundos — resposta lenta conta como falha, ainda que o código seja 200.

401 ao consultar o pagamento

O data.id recebido pertence à conta cujas credenciais criaram o pagamento. Um erro comum é receber a notificação da conta de teste e consultar a API com o access token de produção (ou de outra aplicação). Notificação e consulta precisam usar o mesmo par de credenciais.

Notificações duplicadas

O Mercado Pago reenvia notificações não confirmadas em ciclos de até 15 minutos — e às vezes o mesmo evento chega duas vezes mesmo com tudo certo. Trate o processamento como idempotente: use o data.id + status consultado como chave e ignore repetições. É o mesmo princípio geral de qualquer webhook, detalhado em Os 10 erros mais comuns ao implementar webhooks.

Notificação de teste processada como venda real

Toda notificação traz live_mode no corpo, e o pagamento consultado também tem o campo. Cheque-o antes de liberar qualquer coisa — pedidos "pagos" com credenciais de teste em produção são um clássico constrangedor.

Boleto "atrasado"

Pix notifica em segundos; boleto só muda de status na compensação bancária (até 3 dias úteis). Não é bug — é o meio de pagamento. Modele seus estados internos para conviver com pagamentos pendentes por dias.

Resumo

  • Use Webhooks (não IPN): tópico payment, URL HTTPS por modo (teste/produção), assinatura secreta guardada.
  • Valide o x-signature com o manifest oficial id:[data.id];request-id:[x-request-id];ts:[ts]; e HMAC-SHA256.
  • Responda 200 em menos de 22 segundos e processe em fila; o status real vem de GET /v1/payments/{id}, nunca do corpo do webhook.
  • Idempotência pelo data.id, checagem de live_mode e credenciais consistentes entre notificação e consulta.
  • Teste com contas de sandbox, simulador do painel e um endpoint de inspeção antes de codar.