Ferramenta grátis · Mercado Pago
Validar a assinatura de um webhook
do Mercado Pago (x-signature)
Cole o que o Mercado Pago enviou e veja se a assinatura confere, qual manifest foi assinado e o hash esperado ao lado do recebido. Feito para quando o seu handler de webhooks responde 401 e você não sabe por quê.
Tudo é calculado no seu navegador. A assinatura é calculada nesta página com a Web Crypto API. Nada do que você digita é enviado a algum servidor e o segredo não sai desta página.
Como o Mercado Pago assina um webhook
Cada notificação de webhook traz uma assinatura HMAC-SHA256 para você provar que ela veio do Mercado Pago e não é um replay. Verificá-la leva cinco passos.
- 01
Separe o header x-signature
O header tem este formato: x-signature: ts=1704908010,v1=618c8534…. Divida por vírgulas e depois pelo primeiro sinal de igual de cada parte. ts é o timestamp da assinatura (o exemplo oficial tem 10 dígitos, ou seja, segundos; aceite segundos ou milissegundos) e v1 é o hash.
- 02
Reúna as três entradas
data.id vem da query string da URL da notificação (?data.id=123456), x-request-id é um header da requisição e ts vem do passo um.
- 03
Monte o manifest
Concatene id:<data.id>;request-id:<x-request-id>;ts:<ts>; exatamente assim, com o ponto e vírgula final. Se data.id ou x-request-id estiver ausente, omita o segmento inteiro. O SDK de Go converte o data.id para minúsculas antes de usá-lo.
- 04
Calcule o HMAC-SHA256
Assine o manifest usando como chave o segredo de webhook da sua aplicação e pegue o digest em hexadecimal minúsculo.
- 05
Compare e depois confira o timestamp
Compare o seu digest com v1 em tempo constante e rejeite a requisição se ts for antigo demais. Uma janela de cinco minutos é uma escolha comum.
A mesma verificação em Node.js
Uma implementação sem dependências dos cinco passos, com node:crypto. Coloque numa rota do Express ou do Next.js e chame com os headers da requisição, o parâmetro data.id e o seu segredo.
1 import { createHmac, timingSafeEqual } from 'node:crypto';
2
3 export function verifyMercadoPagoWebhook(req, secret: string): boolean {
4 const xSignature = req.header('x-signature') ?? '';
5 const xRequestId = req.header('x-request-id') ?? '';
6 const dataId = String(req.query['data.id'] ?? '').toLowerCase();
7
8 const parts = Object.fromEntries(
9 xSignature.split(',').map((p) => p.trim().split('=')),
10 );
11 const { ts, v1 } = parts;
12 if (!ts || !v1) return false;
13
14 let manifest = '';
15 if (dataId) manifest += `id:${dataId};`;
16 if (xRequestId) manifest += `request-id:${xRequestId};`;
17 manifest += `ts:${ts};`;
18
19 const expected = createHmac('sha256', secret).update(manifest).digest('hex');
20 const a = Buffer.from(expected);
21 const b = Buffer.from(v1);
22 if (a.length !== b.length || !timingSafeEqual(a, b)) return false;
23
24 // Replay protection: reject a signed timestamp older than 5 minutes.
25 // Mercado Pago's example ts has 10 digits (seconds); accept seconds or milliseconds.
26 const tsMs = Number(ts) < 1e12 ? Number(ts) * 1000 : Number(ts);
27 return Math.abs(Date.now() - tsMs) <= 5 * 60 * 1000;
28 }
Por que a minha assinatura do Mercado Pago é inválida?
Por que a assinatura do meu webhook do Mercado Pago não confere?+
O data.id precisa estar em minúsculas?+
De onde vem o data.id?+
Posso usar o segredo de outra aplicação?+
A assinatura é válida aqui, mas o meu servidor a rejeita. Por quê?+
É seguro colar o meu segredo de webhook aqui?+
Quais notificações trazem o header x-signature?+
| Preço | Founder $99 ou Lifetime $199, pagamento único (sem assinatura) |
|---|---|
| Licença | Código-fonte completo, uso comercial, projetos ilimitados. O Founder é uma versão congelada; o Lifetime inclui todas as versões futuras. |
| Stack | Frontend em Next.js, API em Express, runtime Bun, Prisma, BetterAuth |
| Autenticação | BetterAuth: sessões, 2FA, magic links, redefinição de senha |
| Multi-tenancy e RBAC | Organizações com membros, convites, papéis e permissões |
| Pagamentos | Polar: cobrança completa (checkout, portal do cliente, webhooks, sincronização de planos). MercadoPago: pagamentos únicos com Checkout Pro e webhooks assinados; as assinaturas ainda não são suportadas. Stripe: scaffold de adapter, ainda não cobra. |
| Guardrails para agentes de IA | Camadas de arquitetura forçadas com ESLint, hooks do Claude Code e um AGENTS.md |
| Reembolso | 14 dias |
| Teste: conta grátis | Cadastre-se grátis e explore o dashboard: organizações, papéis, cobrança, log de auditoria. A licença é comprada por dentro. https://usedeploy.dev/register |
| Docs | Documentação em inglês, com traduções para espanhol e português dos guias principais |