Todos los artículos

Integraciones · 25 de julio de 2026 · 12 min de lectura

Webhooks de Mercado Pago y Pix: guía completa de integración y pruebas

Un pago con Pix — el sistema de pagos instantáneos de Brasil — se confirma en segundos, y tu sistema necesita enterarse al instante, sin consultar la API de Mercado Pago en un loop. Para eso existen los webhooks de notificación. En esta guía vas a configurar las notificaciones desde cero, validar la firma x-signature, armar el flujo completo de un pago Pix y probar todo antes de salir a producción — incluidos los errores que más traban las integraciones reales.

Por qué Mercado Pago notifica vía webhook

Cuando un cliente paga con Pix, la aprobación ocurre en segundos; con tarjeta, el estado puede pasar de in_process a approved o rejected minutos después; con boleto — un comprobante bancario brasileño que se paga en efectivo o desde la app del banco —, días después. Consultar la API cada pocos segundos por cada orden abierta no escala y además choca con los rate limits. El modelo invertido lo resuelve: Mercado Pago envía un POST a tu URL cada vez que ocurre algo relevante, y tu aplicación reacciona al momento.

Históricamente existieron dos mecanismos: el IPN (Instant Payment Notification), hoy discontinuado, y los Webhooks, que son el camino recomendado y el único que deberías usar en integraciones nuevas. Toda la documentación oficial está en la página de notificaciones Webhooks de Mercado Pago. Si todavía no dominás el funcionamiento general de los webhooks (reintentos, idempotencia, respuesta rápida), conviene empezar por nuestra guía Qué es un webhook y cómo funciona.

Configurando las notificaciones

Desde el panel de desarrollador

  1. Entra a Tus integraciones, selecciona tu aplicación y abre Webhooks → Configurar notificación.
  2. Registra la URL de tu endpoint — obligatoriamente HTTPS válido y accesible desde internet. Hay dos campos separados: modo prueba (usado con credenciales de prueba) y modo producción.
  3. Selecciona los eventos que quieres recibir. Para pagos (Pix, tarjeta, boleto), el tópico es payment, que dispara las acciones payment.created y payment.updated.
  4. Guarda la firma secreta que se muestra en esa pantalla — con ella vas a validar el header x-signature. Puede regenerarse en cualquier momento (y en ese caso hay que actualizar tu entorno).

Vía API, por pago

Alternativamente (o en conjunto), puedes informar el campo notification_url al crear el pago o la preferencia de checkout. Es útil cuando cada tienda o tenant de tu sistema tiene su propio endpoint. La notificación llega en el mismo formato; la única diferencia es dónde se definió la URL.

Qué llega a tu endpoint

La notificación es un POST con el identificador del recurso en la query string (data.id y type) y un cuerpo 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" }
}

El flujo completo de un Pix, paso a paso

  1. Creas el pago Pix y muestras el código QR al cliente.
  2. El cliente paga en la app de su banco; Mercado Pago aprueba en segundos.
  3. Mercado Pago envía la notificación (action: payment.updated) a tu URL, con la firma en el header x-signature.
  4. Tu endpoint valida la firma y responde 200 de inmediato — Mercado Pago espera la respuesta unos 22 segundos; sin ella, considera la entrega fallida y la reenvía después.
  5. Fuera del ciclo de la respuesta, tu aplicación consulta GET /v1/payments/12345678901 con el access token de la cuenta.
  6. Si status = "approved", la orden se libera; cualquier otro estado solo actualiza el registro interno.

En código (Node + Express), el esqueleto del handler queda así:

handler del webhook — responde rápido, procesa después
app.post("/webhooks/mercadopago", async (req, res) => {
  // 1. Rechaza solicitudes sin firma válida (ver sección de abajo)
  if (!firmaValida(req)) return res.sendStatus(401);

  // 2. Confirma la recepción ya — sin esperar el procesamiento
  res.sendStatus(200);

  // 3. El trabajo pesado va a una cola, nunca en el ciclo de la respuesta
  const { type, data } = req.body;
  if (type === "payment") {
    await cola.add("procesar-pago", { paymentId: data.id });
  }
});
en el worker — la API es la fuente de verdad
const resp = await fetch(
  `https://api.mercadopago.com/v1/payments/${paymentId}`,
  { headers: { Authorization: `Bearer ${process.env.MP_ACCESS_TOKEN}` } },
);
const pago = await resp.json();

if (pago.status === "approved" && pago.live_mode) {
  await liberarOrden(pago.external_reference);
}

Validando la firma x-signature

Tu endpoint es público — cualquiera que descubra la URL puede enviar un POST con un JSON idéntico al de Mercado Pago. La firma es lo que separa una notificación legítima de una falsificada. El header llega en este formato:

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

La validación tiene cuatro pasos:

  1. Extrae ts y v1 del header x-signature.
  2. Arma el manifest con el template oficial: id:[data.id];request-id:[x-request-id];ts:[ts]; — usando el data.id de la query string y el header x-request-id.
  3. Calcula el HMAC-SHA256 del manifest en hexadecimal, usando la firma secreta del panel como clave.
  4. Compara el resultado con v1 usando comparación de tiempo constante.
validación de la firma en Node
import crypto from "node:crypto";

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

  const partes = Object.fromEntries(
    firma.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 vale la pena suscribir

Evento (action)Cuándo se disparaQué hacer
payment.createdPago creado: Pix pendiente, boleto emitido, tarjeta en análisisRegistrar el pago y esperar la actualización
payment.updatedEl estado cambió: aprobado, rechazado, devuelto, canceladoConsultar GET /v1/payments/{id} y actualizar la orden
chargebacksContracargo abierto o modificadoSuspender la entrega y reunir evidencias de la venta
subscription_preapprovalSuscripción creada, pausada o canceladaSincronizar el estado de la suscripción en tu sistema

Cómo probar antes de salir a producción

  • Cuentas de prueba. Crea un par vendedor/comprador en "Cuentas de prueba" en el panel. El vendedor de prueba tiene credenciales propias — con ellas creas pagos de sandbox y recibes notificaciones en el endpoint de modo prueba.
  • Simulador de notificaciones. En la pantalla de configuración de Webhooks hay un botón de simulación que envía una notificación de ejemplo a tu URL — la forma más rápida de verificar conectividad y validación de firma.
  • Inspecciona primero el payload real. Antes de escribir el handler, apunta la URL de prueba a un endpoint de inspección (una URL temporal que captura y muestra cada solicitud, con headers y body). Ver un x-signature y un cuerpo reales elimina la mitad de las dudas de integración.
  • Desarrollo local. Mercado Pago no alcanza localhost — vas a necesitar un túnel o reenvío de eventos. Las opciones están comparadas en Cómo probar webhooks en localhost.
  • Tarjetas y pagadores de prueba. Usa las tarjetas de prueba documentadas (aprobación, rechazo por saldo, rechazo por seguridad) para simular cada camino de tu flujo, y el Pix de sandbox para el flujo instantáneo.

Troubleshooting: los problemas clásicos

La notificación nunca llega

Casi siempre es infraestructura: URL con HTTPS inválido (certificado vencido o self-signed), firewall/WAF bloqueando las IPs de Mercado Pago, o la URL registrada en el modo equivocado (prueba × producción). Confirma con el simulador del panel y verifica que tu endpoint responda en menos de 22 segundos — una respuesta lenta cuenta como falla, aunque el código sea 200.

401 al consultar el pago

El data.id recibido pertenece a la cuenta cuyas credenciales crearon el pago. Un error común es recibir la notificación de la cuenta de prueba y consultar la API con el access token de producción (o de otra aplicación). Notificación y consulta deben usar el mismo par de credenciales.

Notificaciones duplicadas

Mercado Pago reenvía las notificaciones no confirmadas en ciclos de hasta 15 minutos — y a veces el mismo evento llega dos veces incluso con todo en orden. Trata el procesamiento como idempotente: usa el data.id + el estado consultado como clave e ignora repeticiones. Es el mismo principio general de cualquier webhook, detallado en Los 10 errores más comunes al implementar webhooks.

Notificación de prueba procesada como venta real

Toda notificación trae live_mode en el cuerpo, y el pago consultado también tiene el campo. Revísalo antes de liberar cualquier cosa — órdenes "pagadas" con credenciales de prueba en producción son un clásico vergonzoso.

Boleto "atrasado"

Pix notifica en segundos; el boleto solo cambia de estado con la compensación bancaria (hasta 3 días hábiles). No es un bug — es el medio de pago. Modela tus estados internos para convivir con pagos pendientes durante días.

Resumen

  • Usa Webhooks (no IPN): tópico payment, URL HTTPS por modo (prueba/producción), firma secreta guardada.
  • Valida el x-signature con el manifest oficial id:[data.id];request-id:[x-request-id];ts:[ts]; y HMAC-SHA256.
  • Responde 200 en menos de 22 segundos y procesa en cola; el estado real viene de GET /v1/payments/{id}, nunca del cuerpo del webhook.
  • Idempotencia por data.id, chequeo de live_mode y credenciales consistentes entre notificación y consulta.
  • Prueba con cuentas de sandbox, el simulador del panel y un endpoint de inspección antes de programar.