Prueba las notificaciones de Redsys sin hacer pedidos reales
Pega la notificación que Redsys envió a tu Ds_Merchant_MerchantURL: la herramienta decodifica Ds_MerchantParameters, comprueba Ds_Signature con tu clave de comercio y te dice qué significa Ds_Response. O genera una notificación correctamente firmada y reprodúcela contra tu handler local tantas veces como quieras.
La clave solo se usa para calcular la firma en nuestro servidor; nunca se guarda ni se registra. Usa claves de pruebas cuando puedas.
Captura primero la notificación real
Pon como Ds_Merchant_MerchantURL una URL del inspector (sin registro), haz un pago de prueba en el entorno de pruebas de Redsys y la notificación aparece en directo con sus cabeceras y su cuerpo — después pégala aquí o reenvíala a localhost con la CLI:
npx webhook-toolkit listen --forward http://localhost:3000/redsys/notify
Cómo se calcula la firma
- • HMAC_SHA256_V1: la clave del comercio (base64, del módulo de administración de Redsys) se decodifica a 24 bytes; el número de pedido (Ds_Order) se cifra con 3DES-CBC, IV a cero y relleno con ceros: esa es la clave del pedido.
- • Ds_Signature = base64 de HMAC-SHA256(clave del pedido, Ds_MerchantParameters tal cual se recibió). Las notificaciones usan base64 URL-safe (- y _): normaliza antes de comparar.
- • HMAC_SHA512_V2: los 16 primeros caracteres de la clave son una clave AES-128; el pedido se cifra en AES-CBC (IV a cero, PKCS7) y el texto base64 del resultado es la clave HMAC-SHA512.
- • Firma siempre la cadena Ds_MerchantParameters recibida — nunca un JSON recodificado — y lee Ds_Order de los parámetros decodificados (Ds_Order en notificaciones, DS_MERCHANT_ORDER en peticiones).
import crypto from "node:crypto";
export function redsysSignature(merchantKeyB64, merchantParameters) {
const params = JSON.parse(Buffer.from(merchantParameters, "base64").toString());
const order = Buffer.from(params.Ds_Order ?? params.DS_MERCHANT_ORDER);
const padded = Buffer.alloc(Math.ceil(order.length / 8) * 8);
order.copy(padded);
const des = crypto.createCipheriv("des-ede3-cbc", Buffer.from(merchantKeyB64, "base64"), Buffer.alloc(8));
des.setAutoPadding(false);
const key = Buffer.concat([des.update(padded), des.final()]);
return crypto.createHmac("sha256", key).update(merchantParameters).digest("base64");
}
// compare with Ds_Signature after replacing "-" by "+" and "_" by "/"Preguntas frecuentes
¿Por qué no coincide mi firma de Redsys?
Lo más habitual: la firma se calcula sobre un Ds_MerchantParameters recodificado en vez de la cadena exacta recibida; se compara el base64 URL-safe de Ds_Signature (- y _) con base64 estándar (+ y /); la clave es la de otro terminal o la del entorno de pruebas; o Ds_Order se lee del campo equivocado. La herramienta muestra la firma esperada para ver cuál es.
¿Qué códigos Ds_Response indican un pago correcto?
Del 0000 al 0099 son pagos autorizados. El resto son denegaciones: 0190 denegación genérica, 0184 error de autenticación 3-D Secure, 0116 saldo insuficiente, 9915 cancelado por el cliente, 0101 tarjeta caducada.
¿Puedo probar las notificaciones contra localhost?
Sí. Redsys solo llama a URLs públicas: dale una URL de Webhook Toolkit y ejecuta npx webhook-toolkit listen --forward http://localhost:3000/redsys/notify, o genera aquí una notificación firmada y envíala con el comando curl.
¿Funciona con Bizum?
Sí: los pagos con Bizum pasan por la misma notificación de Redsys con la misma firma; solo cambian los campos del medio de pago.