Free tool · Mercado Pago
Validate a Mercado Pago webhook
signature (x-signature)
Paste what Mercado Pago sent you and see whether the signature matches, which manifest was signed, and the expected hash next to the received one. Built for the moment a webhook handler keeps answering 401 and you cannot tell why.
Everything runs in your browser. The signature is computed on this page with the Web Crypto API. Nothing you type is sent to any server, and the secret never leaves this page.
How Mercado Pago signs a webhook
Every webhook notification carries an HMAC-SHA256 signature so you can prove it came from Mercado Pago and was not replayed. Verifying it takes five steps.
- 01
Split the x-signature header
The header looks like x-signature: ts=1704908010,v1=618c8534…. Split it on commas, then on the first equals sign of each part. ts is the signing timestamp (the official example is 10 digits, which is seconds; accept seconds or milliseconds) and v1 is the hash.
- 02
Collect the three inputs
data.id comes from the query string of the notification URL (?data.id=123456), x-request-id is a request header, and ts comes from step one.
- 03
Build the manifest
Concatenate id:<data.id>;request-id:<x-request-id>;ts:<ts>; exactly like that, with the trailing semicolon. If data.id or x-request-id is missing, leave out that whole segment. The Go SDK lowercases data.id before using it.
- 04
Compute the HMAC-SHA256
Sign the manifest with your application webhook secret as the key and take the lowercase hex digest.
- 05
Compare, then check the timestamp
Compare your digest to v1 with a constant-time comparison, then reject the request if ts is too old. A five-minute window is a common choice.
The same check in Node.js
A dependency-free implementation of the five steps, using node:crypto. Drop it in an Express or Next.js route and call it with the request headers, the data.id query parameter and your secret.
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 }
Why is my Mercado Pago signature invalid?
Why does my Mercado Pago webhook signature not match?+
Does data.id have to be lowercase?+
Where does data.id come from?+
Can I use the secret from a different application?+
My signature is valid here but my server rejects it. Why?+
Is it safe to paste my webhook secret here?+
Which notifications carry the x-signature header?+
Keep going
MercadoPago webhooks done right
The full write-up: timing-safe HMAC verification, verify-then-fetch, and idempotent handlers that survive redelivery and the Checkout Pro sandbox.
MercadoPago integration in useDeploy
Checkout Pro with this signature check, replay protection and a typed billing port already wired.
| Price | Founder $99 or Lifetime $199, one-time payment (no subscription) |
|---|---|
| License | Full source, commercial use, unlimited projects. Founder is a frozen snapshot; Lifetime includes every future release. |
| Stack | Next.js frontend, Express API, Bun runtime, Prisma, BetterAuth |
| Auth | BetterAuth: sessions, 2FA, magic links, password reset |
| Multi-tenancy and RBAC | Organizations with members, invitations, roles and permissions |
| Payments | Polar: full billing (checkout, customer portal, webhooks, plan sync). MercadoPago: Checkout Pro one-time payments with signed webhooks; subscriptions are not supported yet. Stripe: adapter scaffold, not charging yet. |
| Guardrails for AI agents | ESLint-enforced architecture layers, Claude Code hooks and an AGENTS.md |
| Refund | 14 days |
| Try it: free account | Sign up free and explore the dashboard: organizations, roles, billing, audit log. You buy the license from inside. https://usedeploy.dev/register |
| Docs | Documentation in English, with Spanish and Portuguese translations of the main guides |