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
- Acesse Suas integrações, selecione a sua aplicação e abra Webhooks → Configurar notificação.
- 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.
- Selecione os eventos que quer receber. Para pagamentos (Pix, cartão, boleto), o tópico é
payment, que dispara as açõespayment.createdepayment.updated. - 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:
{
"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
- Você cria o pagamento Pix e exibe o QR code para o cliente.
- O cliente paga no app do banco; o Mercado Pago aprova em segundos.
- O Mercado Pago envia a notificação (
action: payment.updated) para a sua URL, com a assinatura no headerx-signature. - Seu endpoint valida a assinatura e responde
200imediatamente — o Mercado Pago aguarda a resposta por cerca de 22 segundos; sem ela, considera falha e reenvia depois. - Fora do ciclo da resposta, sua aplicação consulta
GET /v1/payments/12345678901com o access token da conta. - 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:
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 });
}
});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:
x-signature: ts=1704908010,v1=618c85345248dd820d5fd456117c2ab2ef8eda45...
x-request-id: bb56a2f1-6aae-46ac-982e-9dcd3581d08eA validação tem quatro passos:
- Extraia
tsev1do headerx-signature. - Monte o manifest com o template oficial:
id:[data.id];request-id:[x-request-id];ts:[ts];— usando odata.idda query string e o headerx-request-id. - Calcule o HMAC-SHA256 do manifest em hexadecimal, usando a assinatura secreta do painel como chave.
- Compare o resultado com
v1usando comparação de tempo constante.
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 dispara | O que fazer |
|---|---|---|
payment.created | Pagamento criado: Pix aguardando, boleto emitido, cartão em análise | Registrar o pagamento e aguardar a atualização |
payment.updated | Status mudou: aprovado, recusado, estornado, cancelado | Consultar GET /v1/payments/{id} e atualizar o pedido |
chargebacks | Contestação aberta ou alterada | Suspender a entrega e reunir evidências da venda |
subscription_preapproval | Assinatura criada, pausada ou cancelada | Sincronizar 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-signaturee 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-signaturecom o manifest oficialid:[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 delive_modee credenciais consistentes entre notificação e consulta. - Teste com contas de sandbox, simulador do painel e um endpoint de inspeção antes de codar.