← All guides
Mercado PagoJuly 12, 20266 min read

Test Mercado Pago Webhooks on Localhost Without Deploying

A step-by-step guide to receive, route, and transform a Mercado Pago webhook on localhost with Relayers — signature-safe, no tunnel scripts.

You just wired up a Pix checkout with Mercado Pago. Payment goes through, the buyer sees a confirmation, and then... nothing happens in your app. The payment.created notification is being POSTed somewhere — to a public URL that Mercado Pago requires — but your order-fulfillment code lives on localhost:3000, and Mercado Pago can't reach it.

The usual workarounds are all bad. Deploy to staging on every change and tail remote logs. Spin up a raw tunnel and hope the signature headers survive. Paste the payload into a curl script by hand and lose all fidelity with what production actually sends. None of these let you set a breakpoint in your handler and step through a real notification.

Relayers fixes this. It gives you a stable public ingest URL, forwards the exact request to your machine, and lets you filter and reshape events before they ever hit your code — with the original body and headers untouched, so HMAC signature verification works locally.

What you'll build

Mercado Pago sends its notification to a public URL it can always reach. Relayers receives it, applies your routing rules and transform, then pipes it down a WebSocket tunnel to whatever port your dev server runs on.

Prerequisites

1Create an endpoint in Relayers

Open the desktop app, go to Endpoints, and click Create. Give it a name like mercadopago-dev. Relayers generates a public ingest URL:

https://api.relayers.app/v1/webhooks/wep_abc123

Copy it — you'll paste it into Mercado Pago next. Before leaving the app, hit Send test to fire a sample request at the endpoint so you can confirm it's live.

2Configure the notification URL in Mercado Pago

Mercado Pago supports two ways to tell it where to send notifications.

Option A — the developer panel (recommended for a fixed URL). Go to Your integrations → your app → Webhooks / Notificações, paste your Relayers URL as the Notification URL, and select the events you care about (Payments). Save.

Option B — per request. When you create a payment or preference through the API, pass notification_url:

{
  "transaction_amount": 100.0,
  "description": "Pix order #4821",
  "payment_method_id": "pix",
  "notification_url": "https://api.relayers.app/v1/webhooks/wep_abc123",
  "payer": { "email": "buyer@example.com" }
}

Once configured, Mercado Pago POSTs a compact JSON body on each event:

{
  "type": "payment",
  "action": "payment.created",
  "data": { "id": "1234567890" }
}

Newer webhooks also include an x-signature and x-request-id header so you can validate the request came from Mercado Pago via HMAC. Relayers forwards both headers untouched — more on that below.

Note that the body only carries the payment id. You still fetch the full payment object yourself with a GET /v1/payments/{id} call using that id — the notification is a nudge, not the record.

3Forward events to localhost

In your terminal, start the tunnel:

relayers listen --forward localhost:3000

The CLI opens a WebSocket to Relayers. From now on, every request that arrives at your endpoint is replayed against localhost:3000, method, path, body, and headers intact. Trigger a test payment in the Mercado Pago sandbox and watch it land in your handler in real time. Set a breakpoint — it'll hit.

If you prefer to route in the app, open the endpoint's Rules and set the destination to a tunnel pointing at localhost:3000.

4Route and filter with JQ

Mercado Pago fires notifications for several type values — payment, plan, subscription, invoice, and more. During development you usually only care about payments. Open Rules on your endpoint and add a JQ filter:

{ "type": "payment" }

This matches only requests whose body has type == "payment"; everything else is skipped. Rules are evaluated top-down and first match wins, so if you later add rules for subscriptions or invoices, drag them into the order you want and reorder as needed. Each matching rule has its own destination — one rule can go to your tunnel while another forwards to a public URL.

5Transform the payload

The raw Mercado Pago body is fine, but you can hand your handler exactly the shape it wants. Open Transformations, create one, and pick a language — jq, JSONata, JavaScript, or Go templates. A minimal jq transform:

{ event: .action, paymentId: .data.id }

Given the earlier payload, your handler receives:

{ "event": "payment.created", "paymentId": "1234567890" }

Use the built-in test playground to paste a sample body and see the output before you save. Attach the transform to your rule and the reshaped payload is what gets delivered.

Signature verification still works

This is the part that breaks with most tunneling hacks. Mercado Pago's x-signature header is an HMAC computed over specific request fields (including the data.id and the x-request-id value). If a proxy rewrites the body or drops headers, your local validation fails and you can't tell a real bug from a tooling artifact.

Relayers forwards the original body and headers byte-for-byte. Both x-signature and x-request-id arrive at localhost:3000 exactly as Mercado Pago sent them, so the HMAC check you run in production runs identically on your laptop. Test your signature-validation code for real — no if (isDev) skipVerification shortcuts.

Going to production

When you deploy, point Mercado Pago at your real endpoint. Two clean paths:

Either way, use Import/Export to save your endpoint, rules, and transformations as a JSON bundle and replay the setup in another workspace or a teammate's machine.

Troubleshooting

Wrap-up

Mercado Pago requires a public notification URL, but your code lives on localhost — that's the whole friction. Relayers bridges it: a stable ingest URL, JQ filtering so you only see the events you want, transformations to reshape payloads, and byte-for-byte forwarding that keeps x-signature validation honest. You debug real Pix and card notifications against your dev server, breakpoints and all, then flip the destination to production when you're ready.

Ready to stop deploying just to see a webhook? Create a free endpoint at relayers.app and download the app to start forwarding in minutes.