Cómo integrar una pasarela de pagos QR en Laravel
Tutorial para integrar pagos QR en una app Laravel: crear el cobro, mostrar el QR y verificar el webhook con HMAC.
Tutorial para integrar pagos QR en una app Laravel: crear el cobro, mostrar el QR y verificar el webhook con HMAC.
Integrar una pasarela de pagos Laravel con QR es una de las formas más rápidas de aceptar cobros digitales en tu e-commerce peruano. Laravel, como framework PHP, te permite consumir APIs REST de forma limpia con Guzzle y manejar webhooks de manera eficiente. En este tutorial verás el flujo completo: crear el cobro, mostrar el QR, recibir la confirmación en tiempo real y verificar la firma HMAC-SHA256.
Una pasarela de pagos Laravel es un servicio externo que se conecta a tu aplicación Laravel mediante una API para procesar cobros. Cuando hablamos de pagos QR, nos referimos a un esquema donde el comercio genera un QR dinámico único con monto fijo y referencia, y el cliente lo escanea desde Yape, Plin o cualquier billetera interoperable conectada al sistema del BCRP.
A diferencia de un QR estático reutilizable, el QR dinámico expira en 15 minutos y está asociado a una transacción concreta. Esto reduce el riesgo de pagos mal aplicados o duplicados. Para un e-commerce construido en Laravel, integrar una pasarela de este tipo implica:
POST a la API.Esta integración es ideal para tiendas online que quieren eliminar la validación manual de capturas de pantalla y ofrecer una experiencia de pago sin fricción.
Antes de programar, asegúrate de cumplir con estos requisitos. Trabajar con una pasarela de pagos Laravel exige orden en las credenciales y en el entorno de desarrollo.
Necesitarás un par de claves API: una clave pública o de comercio y una clave secreta. Para pruebas, solicita las claves de sandbox en el panel de tu proveedor. Nunca uses las claves de producción en local; los entornos separados evitan cobros accidentales.
Revisa la documentación para developers de tu pasarela. Si existe un SDK oficial de PHP, aprovéchalo: reduce el tiempo de integración y maneja detalles como autenticación y reintentos. En este tutorial asumiremos que trabajas con una API REST estándar, similar a la de TAYPI, que expone POST /api/v1/payments para crear cobros.
Necesitarás saber crear controladores, rutas y usar Http (Guzzle) para consumir APIs. También es recomendable configurar una cola de trabajo para procesar webhooks sin bloquear la respuesta HTTP.
| Método de integración | Control | Complejidad | Tiempo estimado | Mantenimiento |
|---|---|---|---|---|
| API REST directa | Alto | Media | 1 día aprox. | Manual |
| SDK oficial de PHP | Medio-alto | Baja | Unas horas | Automatizado |
| Checkout.js | Bajo | Muy baja | Minutos | Delegado en el proveedor |
El primer paso es crear una transacción. Con una pasarela de pagos QR como TAYPI, envías una petición POST /api/v1/payments con los datos del cobro: monto, moneda, referencia interna del pedido y, opcionalmente, datos del cliente.
Puedes crear un servicio PaymentService en app/Services y consumir la API con el cliente Illuminate\Support\Facades\Http:
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('TAYPI_API_KEY'),
'X-Idempotency-Key' => $order->uuid,
])->post('https://api.taypi.pe/api/v1/payments', [
'amount' => 129.90,
'currency' => 'PEN',
'reference' => 'PEDIDO-1001',
'description' => 'Compra en MiTienda.pe',
]);
if ($response->successful()) {
$payment = $response->json();
// Guardar payment_id, qr_url y checkout_url
}
Uno de los errores más comunes en integraciones de pago es duplicar un cobro cuando el cliente reintenta el pago o la API se cae. La idempotencia resuelve esto: envías una clave única por intención de cobro (por ejemplo, el UUID del pedido) y la pasarela garantiza que solo se procesará una vez. Si quieres profundizar, revisa este artículo sobre idempotencia en APIs de pago: por qué es crítica.
Una vez que la API responde, obtienes dos elementos clave: el QR (imagen o datos para generarlo) y un checkout_url con la página de pago. Puedes mostrar el QR directamente en una vista Blade o redirigir al cliente a ese enlace.
Si la respuesta incluye una URL de imagen QR, puedes mostrarla así:
<img src="{{ $payment['qr_url'] }}" alt="QR de pago para pedido {{ $order->reference }}">
Si prefieres redirigir al checkout externo, usa:
return redirect($payment['checkout_url']);
En el esquema de QR dinámico interoperable, el QR expira en 15 minutos. Si el cliente no alcanza a pagar, debes generar un nuevo cobro con una referencia distinta. Muestra un contador regresivo en la interfaz y habilita un botón “Reintentar pago” que cree una nueva intención de cobro.
Para entender mejor cómo funciona el QR dinámico en el ecosistema peruano, consulta qué son los pagos QR interoperables en Perú.
El webhook es la pieza que confirma el pago en tiempo real. Tu proveedor enviará una petición POST a una ruta de tu aplicación, como /webhooks/pagos. Ahí recibirás el estado del cobro y podrás actualizar tu base de datos.
Nunca confíes ciegamente en el contenido del webhook. Debes verificar la firma HMAC-SHA256 que el proveedor incluye en una cabecera específica (por ejemplo, X-Signature). La lógica es simple: construyes un hash a partir del cuerpo crudo de la petición y tu clave secreta, y lo comparas con el hash recibido.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
public function handle(Request $request)
{
$signature = $request->header('X-Signature');
$payload = $request->getContent();
$computed = hash_hmac('sha256', $payload, env('TAYPI_WEBHOOK_SECRET'));
if (!hash_equals($computed, $signature)) {
abort(401);
}
$event = $request->json()->all();
if ($event['status'] === 'confirmed') {
// Marcar el pedido como pagado
}
return response()->json(['ok' => true]);
}
El uso de hash_equals evita ataques de comparación de tiempo. Para una explicación más detallada, revisa cómo verificar firmas HMAC-SHA256 en tu backend. Si quieres diseñar bien el flujo completo, te recomiendo la guía completa de webhooks de pagos en tiempo real.
Cada webhook debe quedar ligado a la referencia original del pedido. Así puedes automatizar la conciliación: al confirmarse el pago, actualizas el estado del pedido, descuentas stock y envías el correo de confirmación. La referencia única es el pegamento entre tu sistema y la pasarela.
Integrar bien una pasarela de pagos Laravel va más allá de hacer funcionar el flujo feliz. Necesitas blindar tu aplicación contra fallos humanos y técnicos.
Antes de procesar dinero real, crea una cuenta de pruebas y usa las claves de sandbox. Simula pagos exitosos, fallidos y pendientes. Verifica que tus webhooks respondan correctamente y que la firma HMAC se valide siempre.
Si tu webhook falla al procesar una confirmación, el proveedor podría reintentar la entrega. Asegúrate de que tu endpoint sea idempotente también del lado receptor: si recibes dos veces el mismo evento de pago, no dupliques el pedido ni envíes dos correos. Puedes guardar el event_id y descartar duplicados.
Cuando la API de cobro devuelva un error por monto inválido, moneda no soportada o falta de fondos, muestra un mensaje claro al cliente. Crea excepciones personalizadas en Laravel y registra los intentos en logs. La robustez de tu integración es parte de la experiencia de compra.
TAYPI es una pasarela de pagos con QR interoperable para e-commerce y comercios en Perú. Su API REST permite implementar el flujo que acabamos de describir sin fricciones. Algunas ventajas concretas para tu aplicación Laravel:
Además, TAYPI cumple con la regulación peruana PLAFT y opera sobre la infraestructura de pagos interoperables del BCRP. Si quieres conocer más sobre la seguridad de esta pasarela, visita seguridad de TAYPI.
La integración no tiene costo fijo si la haces tú mismo. La pasarela cobra una comisión por transacción confirmada. En el caso de TAYPI, la fórmula es (monto × 2.50% + número_de_cobros × S/ 0.20) × 1.18. En un cobro de S/ 100, la comisión total es S/ 3.19 y el comercio recibe S/ 96.81.
No es obligatorio, pero ayuda. Puedes consumir la API REST directamente con Guzzle o el facade Http de Laravel. TAYPI ofrece un SDK oficial de PHP, ideal para Laravel, que simplifica la integración y maneja la autenticación.
Usa claves de idempotencia en cada petición de creación de cobro. Envía una clave única por pedido, como el UUID del carrito. Así, aunque el cliente reintente la petición o la red falle, la pasarela solo procesará una transacción.
El QR dinámico expira. Debes generar un nuevo cobro con una referencia distinta. En tu interfaz, muestra un botón “Generar nuevo QR” y crea otra intención de pago.
El checkout_url es la página de pago a la que rediriges al cliente. El webhook es una notificación que tu servidor recibe desde la pasarela cuando el pago se confirma, se rechaza o expira. Ambos son complementarios: el checkout para pagar, el webhook para actualizar tu base de datos sin depender del navegador del cliente.
Integrar una pasarela de pagos Laravel con QR es totalmente viable para un desarrollador con conocimientos básicos del framework. El flujo de crear el cobro, mostrar el QR y verificar el webhook con HMAC-SHA256 te permite automatizar pagos en tiempo real sin fricciones manuales. Si sigues las buenas prácticas de idempotencia, sandbox y conciliación, tendrás una integración robusta y segura.
TAYPI es una opción sólida para este tipo de integración en Perú: QR interoperable, verificación directa con la entidad financiera, comisión simple y liquidación T+1. Para empezar, revisa la documentación para developers o crea una cuenta gratis.
¿Listo para cobrar con QR en tu aplicación Laravel? Crea tu cuenta gratis en TAYPI y prueba el flujo completo con claves de sandbox en menos de un día.
Crea tu cuenta gratis y genera tu primer QR en minutos.
Abrir cuenta gratis