InicioPago con YapePago con QRPreciosSeguridadDevelopersBlog Ingresar Crear cuenta
Blog / Developers
Developers · 04 ago 2026 · 12 min de lectura · por TAYPI

Cómo integrar pagos QR en Node.js y Express

Guía para aceptar pagos QR en Node.js con Express: crea el cobro, escucha el webhook y confirma el pago.

Aceptar pagos QR en Node.js y Express es una de las formas más rápidas de eliminar la fricción en el checkout de tu e‑commerce o aplicación web. En esta guía te muestro cómo integrar un sistema de cobro con QR interoperable (compatible con Yape, Plin y cualquier billetera del ecosistema BCRP) utilizando la API de una pasarela moderna, creando el cobro, escuchando el webhook de confirmación y verificando la firma en tiempo real, todo con código limpio y seguro.

Pagos QR Node.js Express: ventajas para tu e‑commerce

Antes de escribir la primera línea de código, conviene entender por qué los pagos QR son una decisión estratégica para un negocio peruano que opera sobre Node.js.

  • Interoperabilidad real, no solo con una app: el QR que generas es leído por Yape, Plin y cualquier billetera o banco conectado a la Cámara de Compensación Electrónica (CCE) del BCRP. Esto reduce la fricción para el cliente y aumenta la conversión.
  • Cero contracargos (chargebacks): a diferencia de las tarjetas de crédito o débito, los pagos con billetera no se pueden revertir por desconocimiento o disputa. Para tu negocio significa menos estrés operativo y un flujo de caja más predecible.
  • Sin terminal físico ni POS adicional: el QR se muestra en pantalla o se envía por email, lo que lo hace ideal para e‑commerce, aplicaciones móviles progresivas (PWA) e incluso para ventas asistidas por chat.
  • Verificación bancaria directa: la pasarela confirma el pago consultando a la entidad financiera, no con capturas de pantalla. Si el webhook te dice que el pago está confirmado, el dinero ya está en camino.
  • Integración ligera y rápida: con solo unas cuantas llamadas REST, Express y el módulo crypto de Node.js tienes todo lo necesario para poner el flujo en producción en cuestión de horas.

Si quieres profundizar en cómo funciona la interoperabilidad y por qué es un estándar en Perú, puedes leer nuestra guía sobre cómo funciona la interoperabilidad QR del BCRP. Además, conviene entender qué es la CCE y por qué importa para tu negocio.

Requisitos previos para la integración

Para seguir esta guía necesitas:

  • Node.js (versión 16 o superior) y Express instalado en tu proyecto.
  • Una cuenta de comercio en la pasarela de pagos que elijas. Por ejemplo, al registrarte en TAYPI obtienes acceso inmediato al panel, clave de API y entorno sandbox para pruebas.
  • Tus API Keys: una clave pública (para identificar tu comercio en el front, si usas Checkout.js) y una clave secreta (nunca la expongas en el frontend; solo en tu backend de Node.js) que usarás para firmar solicitudes y verificar webhooks.
  • Un endpoint público (o un túnel local con ngrok durante el desarrollo) que reciba los webhooks de notificación de pago.

Todos los secretos deben manejarse mediante variables de entorno. En producción, usa process.env y nunca los hardcodees en tu código fuente.

Si aún no tienes una cuenta, puedes consultar la documentación para developers y ver el detalle de la API REST.

Configurando el entorno de desarrollo Node.js y Express

Crea un proyecto nuevo o añade las rutas necesarias en tu aplicación existente. Vas a necesitar las siguientes dependencias:

npm install axios dotenv express

axios se encargará de las peticiones HTTP a la API de pagos; dotenv cargará las variables de entorno; express levantará el servidor y gestionará las rutas.

Crea un archivo .env (y añádelo a .gitignore):

PAYMENT_API_URL=https://api.pasarela-ejemplo.com/v1
PAYMENT_API_KEY=tu_api_key_secreta
PAYMENT_WEBHOOK_SECRET=tu_secreto_para_webhooks

En tu app.js o server.js configuras las rutas básicas:

require('dotenv').config();
const express = require('express');
const app = express();

app.use(express.json());

// tus rutas aquí...

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Servidor corriendo en puerto ${PORT}`);
});

Ahora estás listo para escribir los endpoints de cobro y de notificación.

Generando un cobro QR dinámico con la API

El flujo de cobro con QR se dispara desde tu backend cuando el cliente decide pagar. La API expone un endpoint POST /api/v1/payments que devuelve, entre otras cosas, la imagen del QR en formato base64 y una URL de pago (checkout_url) que puedes mostrar en tu interfaz o redirigir al usuario.

Parámetros de la solicitud

CampoTipoRequeridoDescripción
amountdecimalMonto total del cobro. Mínimo S/ 1.00.
descriptionstringConcepto del pago (se muestra al cliente).
referencestringNo (recomendado)Tu identificador interno de la orden. Sirve para conciliación.
expires_inintegerNoTiempo de expiración en minutos (por defecto 15). El QR dinámico deja de ser válido tras este plazo.
customerobjectNoDatos opcionales del cliente (ej. { email, name }).

Además, debes incluir el header Idempotency-Key con un valor único generado por ti (por ejemplo, el order_id o un UUID). Esto evita que, por un reintento accidental, se cree un cobro duplicado.

Código del endpoint /api/checkout

const axios = require('axios');
const { v4: uuidv4 } = require('uuid'); // opcional

app.post('/api/checkout', async (req, res) => {
  try {
    const { amount, description, reference } = req.body;

    if (!amount || !description) {
      return res.status(400).json({ error: 'amount y description son obligatorios' });
    }

    const idempotencyKey = reference || uuidv4();

    const response = await axios.post(
      `${process.env.PAYMENT_API_URL}/payments`,
      {
        amount,
        description,
        reference,
        expires_in: 15,
      },
      {
        headers: {
          Authorization: `Bearer ${process.env.PAYMENT_API_KEY}`,
          'Idempotency-Key': idempotencyKey,
          'Content-Type': 'application/json',
        },
      }
    );

    const { qr_code_base64, checkout_url, id: payment_id } = response.data;

    // Devuelve al frontend lo necesario para mostrar el QR
    res.json({
      payment_id,
      qr_code: qr_code_base64,      // imagen en base64 para incrustar en <img>
      checkout_url,                 // link de pago alternativo
    });
  } catch (error) {
    console.error('Error creando el cobro:', error.response?.data || error.message);
    res.status(500).json({ error: 'Error al generar el cobro QR' });
  }
});

El QR generado es dinámico y único para ese cobro; expira a los 15 minutos y cualquier billetera interoperable (Yape, Plin, etc.) puede leerlo. Tu frontend simplemente muestra la imagen y, en paralelo, queda a la espera de la confirmación vía webhook o polling controlado.

Escuchando el webhook de pago en tiempo real

Tan importante como crear el cobro es confirmar que el cliente pagó. La pasarela envía una notificación HTTP POST a un endpoint que tú definas en el panel (por ejemplo, https://tu-dominio.com/api/webhook). Ese webhook incluye la información del pago y una firma HMAC‑SHA256 en el header X‑Signature que debes verificar para evitar peticiones maliciosas.

Configurar la ruta del webhook en Express

app.post('/api/webhook', (req, res) => {
  try {
    const signature = req.headers['x-signature'];
    const payload = JSON.stringify(req.body);

    // 1. Verificar la firma
    const crypto = require('crypto');
    const expectedSignature = crypto
      .createHmac('sha256', process.env.PAYMENT_WEBHOOK_SECRET)
      .update(payload, 'utf-8')
      .digest('hex');

    if (signature !== expectedSignature) {
      return res.status(401).json({ error: 'Firma inválida' });
    }

    // 2. Procesar el evento
    const event = req.body;
    if (event.status === 'confirmed') {
      // El pago fue confirmado por la entidad financiera
      console.log(`Pago confirmado para la orden ${event.reference}`);

      // Aquí actualizas tu base de datos, envías el producto, etc.
    }

    // 3. Responder 200 rápido para evitar reenvíos
    res.sendStatus(200);
  } catch (error) {
    console.error('Error en el webhook:', error);
    res.status(500).json({ error: 'Error interno' });
  }
});

El paso de verificación de firma es crítico. Si necesitas una explicación detallada de cómo funciona y cómo evitar errores comunes, consulta el artículo sobre cómo verificar firmas HMAC‑SHA256 en tu backend. También es recomendable implementar un pequeño retardo o cola para procesar el evento de manera robusta, pero el concepto base es el que ves arriba.

Pagos QR Node.js Express: seguridad, idempotencia y firma HMAC

El manejo correcto de la seguridad en una API de pagos va más allá del webhook. Dos prácticas que debes adoptar desde el inicio son:

Idempotencia

Al generar un cobro, usas el header Idempotency-Key. Si una solicitud falla por timeout y la reenvías con la misma clave, el backend de la pasarela devuelve el resultado original sin crear un segundo cobro. Esto es vital para que el cliente no termine pagando dos veces sin querer. A nivel de tu aplicación, puedes guardar la clave en una tabla de idempotencia o simplemente confiar en que la pasarela maneja la semántica correcta. Para profundizar, te sugiero leer idempotencia en APIs de pago: por qué es crítica.

Firma HMAC‑SHA256 en los webhooks

Como viste, verificas cada notificación antes de procesarla. Esto asegura que solo las peticiones originadas por la pasarela modifiquen el estado de tus órdenes. Nunca confíes únicamente en la IP de origen o en el contenido sin firma.

Cifrado y cumplimiento

Toda la comunicación viaja sobre TLS 1.3 (HTTPS). Del lado de la pasarela, se cumple con la normativa PLAFT (prevención de lavado de activos) según los lineamientos de la SBS y UIF‑Perú. La infraestructura de pagos opera sobre la CCE del BCRP, lo que te da la tranquilidad de trabajar con un estándar supervisado. La pasarela TAYPI, por ejemplo, cuenta con certificaciones ISO 27001:2022 e ISO 9001:2015, lo que habla de un entorno maduro en seguridad y gestión de calidad.

Probando en sandbox y pasando a producción

La pasarela ofrece un entorno de pruebas (sandbox) donde los pagos no mueven dinero real. Debes usar las claves de sandbox y realizar al menos los siguientes casos:

  • Crear un cobro y visualizar el QR generado.
  • Simular el pago desde la herramienta de simulación del panel (normalmente un botón “Pagar” en el entorno sandbox).
  • Verificar que el webhook llegue a tu endpoint y la firma sea válida.
  • Reintentar un cobro con la misma Idempotency-Key para comprobar que no se duplica.
  • Dejar expirar un QR y ver cómo tu sistema responde (por ejemplo, mostrando un mensaje de “QR expirado, genera uno nuevo”).

Una vez que todo funcione, migras a las credenciales de producción. A partir de ese momento, cada pago confirmado seguirá el ciclo de liquidación: el dinero se deposita en tu cuenta bancaria CCI al día hábil siguiente (T+1), sin saldos retenidos en la pasarela. Para activar la liquidación necesitas completar el proceso de verificación KYB (comercio Nivel 2).

La comisión estándar por pago confirmado es de 2.50% + S/ 0.20 + IGV. Si quieres ver el desgloso con ejemplos y calcular cuánto recibes neto, revisa la página de precios de TAYPI. No hay costos de instalación, mensualidades ni permanencia, lo que hace que la integración sea rentable incluso para ticket bajo.

Preguntas frecuentes

¿Qué ocurre si el cliente no paga antes de que venza el QR?

El QR dinámico expira en 15 minutos (o el tiempo que hayas configurado). Si el cliente intenta escanearlo después, el pago no se procesa. Tu sistema debe manejar este caso mostrando un mensaje apropiado y ofreciendo la opción de generar un nuevo cobro con la misma referencia.

¿Necesito instalar librerías adicionales para generar el QR?

No. La API devuelve el QR en base64, que puedes incrustar directamente en una etiqueta <img> con el prefijo data:image/png;base64,.... Solo necesitas axios para las peticiones HTTP y crypto (nativo de Node.js) para la verificación de firmas.

¿Cómo sé si el pago está realmente confirmado sin depender solo del webhook?

El webhook es el mecanismo principal, pero también puedes implementar un chequeo proactivo: guarda el payment_id obtenido al crear el cobro y, tras unos minutos, consulta el endpoint GET /api/v1/payments/{id} (si la pasarela lo ofrece) para obtener el estado. La confirmación vía webhook sigue siendo la opción más rápida y recomendada.

¿Es obligatorio verificar la firma HMAC o puedo saltarme ese paso para simplificar el desarrollo?

No, y no debes saltártelo. Si no verificas la firma, cualquiera podría enviar peticiones POST a tu endpoint simulando pagos. La verificación HMAC‑SHA256 es lo que te garantiza que la notificación proviene realmente de la pasarela. Es una capa de seguridad mínima y fácil de implementar con el código que te mostré.

¿La integración con Node.js y Express funciona también para aplicaciones serverless o con Next.js?

Sí. El patrón es el mismo: llamada POST autenticada para crear el cobro y un endpoint que reciba el webhook. En entornos serverless (AWS Lambda, Vercel, etc.) la diferencia es que el manejador del webhook se expone como una función, pero el código de verificación y procesamiento es prácticamente el mismo.

Conclusión

Integrar pagos QR en Node.js y Express es un proyecto que puedes completar en pocas horas siguiendo la arquitectura descrita: generas un cobro con la API, muestras el QR al cliente, escuchas el webhook con verificación HMAC‑SHA256 y aplicas idempotencia para protegerte de duplicados. El resultado es un checkout rápido, compatible con todas las billeteras interoperables del Perú y libre de los contracargos que afectan a las tarjetas.

Si tu negocio ya tiene un backend en Node.js, tienes el 80 % del camino andado. La clave está en manejar bien los secretos, configurar correctamente el webhook y probar cada escenario en sandbox antes de recibir pagos reales. Con una pasarela de pagos QR que opera sobre los carriles del BCRP, como TAYPI, te beneficias de la liquidación T+1, la verificación bancaria directa y un modelo de comisiones transparente que solo cobra por transacción confirmada: sin mensualidades y sin montos retenidos.

Da el siguiente paso y automatiza los cobros de tu aplicación.


¿Listo para empezar? Crea tu cuenta gratis en TAYPI y activa tu entorno sandbox para hacer las primeras pruebas hoy mismo, sin costo de instalación ni compromiso de permanencia.

¿Listo para cobrar con QR?

Crea tu cuenta gratis y genera tu primer QR en minutos.

Abrir cuenta gratis
Quiero afiliarme