Redsys - Biblioteca PHP para Pasarela de Pagos

March 7, 2026 · View on GitHub

Latest Version on Packagist Software License Total Downloads Run Tests

Biblioteca PHP para integrar la pasarela de pagos Redsys/Sermepa (Santander, Sabadell, LaCaixa, BBVA, etc.)

Requisitos

  • PHP 7.1.3+ a 8.2
  • ext-curl
  • ext-openssl
  • ext-json

Instalación

composer require sermepa/sermepa

Inicio Rápido

use Sermepa\Tpv\Tpv;

$redsys = new Tpv();
$redsys->setAmount(2500)           // 25.00€
    ->setOrder('1234AB')
    ->setMerchantcode('999008881')
    ->setCurrency('978')           // Euros
    ->setTransactiontype('0')       // Autorización
    ->setTerminal('1')
    ->setMethod('C')                // Solo tarjeta
    ->setNotification('https://tusitio.com/notificacion')
    ->setUrlOk('https://tusitio.com/ok')
    ->setUrlKo('https://tusitio.com/ko')
    ->setEnvironment('test');       // Entorno de pruebas

$signature = $redsys->generateMerchantSignature('TU_CLAVE_SECRETA');
$redsys->setMerchantSignature($signature);

echo $redsys->createForm();

Entornos Disponibles

EntornoDescripción
testPruebas (SIS Sandbox)
liveProducción
restTestAPI REST Pruebas
restLiveAPI REST Producción
insiteSandboxInSite Pruebas (JS + REST)
insiteLiveInSite Producción (JS + REST)
insiteRestSandboxInSite REST Pruebas (solo pago)
insiteRestLiveInSite REST Producción (solo pago)

Métodos de Pago

CódigoDescripción
C o TTarjeta
RTransferencia
DDomiciliación
zBizum
pPayPal
NMasterpass
xpayGooglePay / ApplePay

Tipos de Transacción

CódigoDescripción
0Autorización
1Preautorización
2Confirmación de preautorización
3Anulación de preautorización
4Devolución
5Cancelación
7Preautorización extendida
8Confirmación preautorización extendida
9Baja de preautorización extendida

Códigos de Respuesta

El banco devuelve un código en Ds_Response. Los principales:

CódigoSignificado
0000 a 0099Pago aprobado
0100 a 0199Operatoria OK, verificación CVV obligatoria
0200Error de formato
0201Error de firma
0204Error de datos
0209Error de tajeta
0214Fecha de caducidad errónea
0215Error en importe mínimo (no usado)
0290Tarjeta no autorizada
0401Error en posición de tarjeta
0404Error de configuración de comercio
0501Operaciones pendientes
0904Comercio no operativo
0912Emisor no disponible
9912Emisor no disponible
9913Error en comunicación
9914Fallo al conectar con CA
9919Error de cryptograma
9929Error de deslinde
9932Error de bin
9933Error de BS. Cambio de dinámico a estático
9934Error de BS. Cambio de estático a dinámico
9951Operación de ingreso OK
9952Operación de ingreso NO OK
9953Devolución OK
9954Devolución NO OK
9955Anulación OK
9956Anulación NO OK
9957Ajuste OK
9958Ajuste NO OK
9961Error en cierre batch
9962Error en apertura batch
9963Error de operativa
9992Petición cancelada
9993Operatoria abandonada por el usuario
9995Operatoria abandonada - tiempo excedido
9996Error de conexión
9997Error de timeout
9998Error de validación
9999Error general

Nota: Para pagos exitosos, el código debe estar entre 0000 y 0099. Convertir a entero para comparar: $DsResponse = (int) $parameters['Ds_Response'];

Validar Respuesta del Banco

En tu URL de notificación (setNotification), debes validar la respuesta del banco:

use Sermepa\Tpv\Tpv;
use Sermepa\Tpv\TpvException;

try {
    $redsys = new Tpv();
    $key = 'TU_CLAVE_SECRETA';

    // Decodificar parámetros recibidos
    $parameters = $redsys->getMerchantParameters($_POST['Ds_MerchantParameters']);
    $DsResponse = (int) $parameters['Ds_Response'];

    // Validar firma y respuesta
    if ($redsys->check($key, $_POST) && $DsResponse <= 99) {
        // Pago correcto -Ds_Response = 0000 a 0099
        // Aquí: actualizar pedido, enviar email, etc.
    } else {
        // Pago fallido
    }
} catch (TpvException $e) {
    error_log('Error TPV: ' . $e->getMessage());
}

Pago con Tarjeta Guardada (Token)

Guardar la tarjeta del cliente para pagos futuros:

// 1. Crear referencia (primer pago)
$redsys->setIdentifier();  // Sin parámetros - indica "REQUIRED"

// Respuesta del banco contendrá:
// $parameters['Ds_Merchant_Identifier']
// $parameters['Ds_ExpiryDate']
// 2. Usar referencia (pagos recurrentes)
$redsys->setIdentifier('IDENTIFICADOR_GUARDADO');
$redsys->setMerchantDirectPayment(true);  // Pago directo sin autenticación 3D Secure

Enviar Datos de Tarjeta Directamente

Puedes enviar los datos de la tarjeta para que el usuario no tenga que introducirlos en la pasarela:

$redsys->setPan('4548812049400004');     // Número de tarjeta
$redsys->setExpiryDate('1228');          // Caducidad (AAMM)
$redsys->setCVV2('123');                 // CVV2

Nota: Esta opción requiere que tu comercio tenga autorización del banco para enviar datos de tarjeta directamente.

API REST (Cobros sin formulario)

Para cobros directos sin redirección del usuario:

use Sermepa\Tpv\Tpv;
use Sermepa\Tpv\TpvException;

try {
    $key = 'TU_CLAVE_SECRETA';

    $redsys = new Tpv();
    $redsys->setAmount(2500)
        ->setOrder('1234AB')
        ->setMerchantcode('999008881')
        ->setCurrency('978')
        ->setTransactiontype('0')
        ->setTerminal('1')
        ->setIdentifier('IDENTIFICADOR_GUARDADO')
        ->setMerchantDirectPayment(true)
        ->setVersion('HMAC_SHA256_V1')
        ->setEnvironment('restTest')
        ->setMerchantCofIni('N');

    $signature = $redsys->generateMerchantSignature($key);
    $redsys->setMerchantSignature($signature);

    $response = json_decode($redsys->send(), true);

    // Verificar error en respuesta
    if (isset($response['errorCode'])) {
        throw new Exception("Error: " . $response['errorCode']);
    }

    // Decodificar respuesta
    $parameters = $redsys->getMerchantParameters($response['Ds_MerchantParameters']);
    $DsResponse = (int) $parameters['Ds_Response'];

    if ($redsys->check($key, $response) && $DsResponse <= 99) {
        // Cobro correcto
    }
} catch (TpvException $e) {
    echo 'Error TPV: ' . $e->getMessage();
}

InSite (Pago Embebido)

InSite permite incrustar el formulario de pago directamente en tu página web mediante un iframe, sin redirigir al usuario a la pasarela de Redsys. Los datos de tarjeta nunca pasan por tu servidor (cumplimiento PCI DSS).

Nota: Tu dominio debe estar registrado en Redsys para usar InSite. Configura los dominios permitidos en el Portal de Administración del TPV Virtual. Contacta con tu banco o soporte de Redsys.

Flujo de Integración

  1. Generar formulario InSite - Renderiza el iframe en tu página
  2. Usuario completa pago - Introduce datos en el iframe de Redsys
  3. Obtener ID de operación - Redsys retorna un idOper (válido por 30 minutos)
  4. Ejecutar pago - Envía el idOper mediante REST API

Paso 1: Generar Formulario InSite (Modo Unificado)

El modo unificado genera un iframe completo con todos los campos de pago:

use Sermepa\Tpv\Tpv;
use Redsys\Merchant\MerchantInsiteLanguage;

$redsys = new Tpv();
$redsys->setEnvironment('insiteSandbox')  // o 'insiteLive' para producción
    ->setOrder('1234AB')
    ->setMerchantcode('999008881')        // Tu código de comercio (FUC)
    ->setTerminal('1');

// Generar HTML del formulario InSite
$htmlForm = $redsys->createInSiteForm(
    'card-form',              // ID del contenedor
    'background: #007bff;',   // Estilo del botón
    'color: white;',          // Estilo del cuerpo
    'padding: 10px;',         // Estilo de la caja de datos
    'font-size: 14px;',       // Estilo de los inputs
    'Pagar',                  // Texto del botón (HTML encoded: 'Bot&#243;n' para Botón)
    MerchantInsiteLanguage::ISO_ES, // Idioma: 'ES', '1', etc.
    true,                     // Mostrar logo de entidad
    false,                    // Estilo reducido
    'inline'                  // Estilo InSite: 'inline' o 'twoRows'
);

echo $htmlForm;

Modo JSON (Recomendado)

Para mayor flexibilidad, usa el método JSON:

$htmlForm = $redsys->createInSiteFormJSON([
    'id' => 'card-form',
    'fuc' => '999008881',
    'terminal' => '1',
    'order' => '1234AB',
    'styleButton' => 'background: #007bff; color: white;',
    'styleBody' => 'font-family: Arial;',
    'styleBox' => 'padding: 10px;',
    'buttonValue' => 'Pagar ahora',
    'idiomaInsite' => 'ES',
    'mostrarLogoInsite' => true,
    'estiloReducidoInsite' => false,
    'estiloInsite' => 'inline'  // o 'twoRows'
]);

Parámetros del Formulario

ParámetroObligatorioDescripción
id / $containerIdID del contenedor div
fuc / merchantCodeCódigo de comercio (FUC)
terminalNúmero de terminal
orderNúmero de pedido (4-12 caracteres)
styleButtonNoCSS para el botón de pago
styleBodyNoCSS para el cuerpo del formulario
styleBoxNoCSS para la caja de datos
styleBoxTextNoCSS para el texto de los inputs
buttonValueNoTexto del botón (HTML encoded)
idiomaInsiteNoCódigo de idioma (ver tabla)
mostrarLogoInsiteNoMostrar logo de entidad (default: true)
estiloReducidoInsiteNoUsar estilo reducido (default: false)
estiloInsiteNo'inline' o 'twoRows' (default: 'inline')

Catálogo de Idiomas InSite

IdiomaCódigo SISISO 639-1
Español1ES
Inglés2EN
Catalán3CA
Francés4FR
Alemán5DE
Italiano7IT
Portugués9PT
.........

Usa las constantes de MerchantInsiteLanguage:

use Redsys\Merchant\MerchantInsiteLanguage;

$redsys->createInSiteForm(..., MerchantInsiteLanguage::SPANISH, ...);
// o
$redsys->createInSiteForm(..., MerchantInsiteLanguage::ISO_ES, ...);

Paso 2: Recibir ID de Operación

El formulario incluye automáticamente un listener que almacena el idOper en un campo hidden:

<input type="hidden" id="token" name="token" value="">
<input type="hidden" id="errorCode" name="errorCode" value="">

Puedes personalizar la validación:

function merchantValidation() {
    // Tu validación personalizada
    return true;  // true para continuar, false para cancelar
}

window.addEventListener("message", function receiveMessage(event) {
    storeIdOper(event, "token", "errorCode", merchantValidation);
});

Códigos de Error InSite

CódigoDescripción
msg1Ha de rellenar los datos de la tarjeta
msg2La tarjeta es obligatoria
msg3La tarjeta ha de ser numérica
msg15La longitud de la tarjeta no es correcta
msg16Debe introducir un número de tarjeta válido
msg17Validación incorrecta por parte del comercio
msg18Error de inicialización de dominio

Usa MerchantInsiteError para obtener descripciones:

use Redsys\Merchant\MerchantInsiteError;

$errorDescription = MerchantInsiteError::getDescription('msg1');

Paso 3: Ejecutar Pago con ID de Operación

use Sermepa\Tpv\Tpv;
use Sermepa\Tpv\TpvException;

try {
    $key = 'TU_CLAVE_SECRETA';
    $idOper = $_POST['token'];    // ID recibido del iframe
    $order = '1234AB';             // Mismo pedido usado en el formulario

    $redsys = new Tpv();
    $redsys->setEnvironment('insiteRestLive')  // o 'insiteRestSandbox'
        ->setAmount(2500)
        ->setOrder($order)          // DEBE ser el mismo que en createInSiteForm
        ->setMerchantcode('999008881')
        ->setCurrency('978')
        ->setTransactiontype('0')
        ->setTerminal('1');

    // Ejecutar pago con el ID de operación
    $response = json_decode($redsys->sendInSite($idOper, $key), true);

    // Decodificar respuesta
    $parameters = $redsys->getMerchantParameters($response['Ds_MerchantParameters']);
    $DsResponse = (int) $parameters['Ds_Response'];

    if ($DsResponse >= 0 && $DsResponse <= 99) {
        // Pago aprobado
    } else {
        // Pago denegado
    }
    }

} catch (TpvException $e) {
    echo 'Error TPV: ' . $e->getMessage();
}

Métodos InSite

MétodoDescripción
setInSite(bool)Habilitar/deshabilitar modo InSite
getInSiteMode()Obtener estado del modo InSite
getInSiteJsUrl()Obtener URL del JavaScript de InSite
createInSiteForm(string $containerId, string $buttonStyle, string $bodyStyle)Generar HTML del formulario embebido
sendInSite(string $idOper, string $key)Ejecutar pago con ID de operación

Personalización del Formulario

// Generar formulario con estilos personalizados
$html = $redsys->createInSiteForm(
    'card-form',                                    // ID del contenedor
    'background-color: #28a745; color: white; padding: 15px; border: none; border-radius: 5px;',  // Estilo botón
    'font-family: Arial, sans-serif;'               // Estilo cuerpo
);

Redirección Automática

Para redirección automática sin mostrar el botón:

$redsys->executeRedirection();
// Opcional: obtener HTML
$html = $redsys->executeRedirection(true);

Integración con JavaScript de Redsys

La biblioteca incluye un método estático para obtener la ruta del JavaScript de Redsys:

use Sermepa\Tpv\Tpv;

// Obtener URL del script
$jsUrl = Tpv::getJsPath('test', '3');  // Entorno test, versión 3
// https://sis-t.redsys.es:25443/sis/NC/sandbox/redsysV3.js
VersiónDescripción
2Redsys Classic
3Redsys API (soporte NFC, Apple Pay, Google Pay)

Constantes Disponibles

Usa las constantes predefinidas para evitar errores de transcripción:

use Redsys\Merchant\MerchantCurrencies;
use Redsys\Merchant\MerchantTransactionTypes;
use Redsys\Merchant\MerchantConsumerLanguages;
use Redsys\Merchant\MerchantPaymethods;

// Monedas
$redsys->setCurrency(MerchantCurrencies::EUR);      // 978
$redsys->setCurrency(MerchantCurrencies::USD);      // 840
$redsys->setCurrency(MerchantCurrencies::GBP);     // 826

// Tipos de transacción
$redsys->setTransactiontype(MerchantTransactionTypes::AUTHORIZATION);  // 0
$redsys->setTransactiontype(MerchantTransactionTypes::PREAUTHORIZATION);  // 1

// Idiomas
$redsys->setLanguage(MerchantConsumerLanguages::SPANISH);   // 001
$redsys->setLanguage(MerchantConsumerLanguages::ENGLISH);   // 002
$redsys->setLanguage(MerchantConsumerLanguages::CATALAN);    // 003

// Métodos de pago
$redsys->setMethod(MerchantPaymethods::CARD);    // C
$redsys->setMethod(MerchantPaymethods::BIZUM);   // z

Códigos de Moneda

Los códigos ISO 4217. Los más comunes:

  • 978 - Euro (EUR)
  • 840 - Dólar estadounidense (USD)
  • 826 - Libra esterlina (GBP)
  • 392 - Yen japonés (JPY)

Códigos de Idioma

CódigoIdioma
001Castellano
002Inglés
003Catalán
004Francés
005Alemán
006Holandés
007Italiano
008Sueco
009Portugués
010Valenciano
011Polaco
012Gallego
013Euskera

API Reference

Métodos de Configuración

MétodoDescripciónRequerido
setAmount(float)Importe (se convierte a céntimos)
setOrder(string)Número de pedido (4-12 caracteres, primeros 4 numéricos)
setMerchantcode(string)Código de comercio (FUC)
setCurrency(string)Código de moneda ISO
setTransactiontype(string)Tipo de transacción
setTerminal(string)Número de terminal
setMethod(string)Método de pagoNo
setNotification(string)URL de notificación (callback)Recomendado
setUrlOk(string)URL si pago exitosoRecomendado
setUrlKo(string)URL si pago fallidoRecomendado
setEnvironment(string)Entorno de conexiónNo
setVersion(string)Versión de firmaNo
setTradeName(string)Nombre del comercioNo
setTitular(string)Titular del pagoNo
setProductDescription(string)Descripción del productoNo

Métodos de Firma y Envío

MétodoDescripción
generateMerchantSignature(string $key)Genera firma HMAC-SHA256
setMerchantSignature(string)Asigna la firma calculada
createForm()Genera formulario HTML
send()Envía petición REST (devuelve JSON)
executeRedirection()Redirección automática con JavaScript

Métodos de Validación

MétodoDescripción
check(string $key, array $postData)Valida firma de respuesta del banco
getMerchantParameters(string)Decodifica Ds_MerchantParameters

Métodos InSite

MétodoDescripción
setInSite(bool)Habilitar modo InSite
getInSiteMode()Obtener estado del modo InSite
getInSiteJsUrl()Obtener URL del JavaScript de InSite
createInSiteForm(...)Genera formulario embebido (modo unificado)
createInSiteFormJSON(array)Genera formulario embebido (modo JSON)
sendInSite(string $idOper, string $key)Ejecuta pago con ID de operación

Parámetros de createInSiteForm()

ParámetroTipoObligatorioDescripción
$containerIdstringNoID del contenedor div (default: 'card-form')
$buttonStylestringNoCSS para el botón de pago
$bodyStylestringNoCSS para el cuerpo del formulario
$boxStylestringNoCSS para la caja de datos
$inputStylestringNoCSS para los inputs
$buttonTextstringNoTexto del botón (HTML encoded)
$languagestringNoCódigo de idioma (default: 'ES')
$showLogoboolNoMostrar logo de entidad (default: true)
$reducedStyleboolNoUsar estilo reducido (default: false)
$insiteStylestringNo'inline' o 'twoRows' (default: 'inline')

Métodos Auxiliares

MétodoDescripción
setNameForm(string)Nombre del formulario
setIdForm(string)ID del formulario
setAttributesSubmit(...)Personalizar botón submit
setLanguage(string)Idioma de la pasarela
setParameters(array)Parámetros adicionales
setIdentifier(string)Referencia de tarjeta guardada
setMerchantDirectPayment(bool)Pago directo sin autenticación
setPan(string)Número de tarjeta
setExpiryDate(string)Caducidad (AAMM)
setCVV2(string)Código CVV2
setMerchantData(string)Datos adicionales del comercio
getOrder()Obtener número de pedido
getParameters()Obtener todos los parámetros
getVersion()Obtener versión de firma
getMerchantSignature()Obtener firma actual
getEnvironment()Obtener URL del entorno
getJsPath(string, string)Obtener ruta JS para integración moderna
createOrderNumber(int)Generar número de pedido válido

Parámetros Avanzados

Pagos Recurrentes

$redsys->setMerchantCofIni('S');           // Inicio de COF
$redsys->setMerchantCofType('R');          // Tipo: R=Recurrente, I=Cuotas
$redsys->setMerchantCofTxnid('123456789'); // ID de transacción
$redsys->setSumtotal(50000);               // Importe total
$redsys->setChargeExpiryDate('2025-12-31'); // Fecha expiración
$redsys->setDateFrecuency(30);             // Frecuencia en días

Excepción SCA (Strong Customer Authentication)

Algunos bancos requieren parámetros adicionales:

$parameters = ['DS_MERCHANT_EXCEP_SCA' => 'MIT'];
$redsys->setParameters($parameters);

Ejemplos Completos

Ejemplo Completo: Pago Simple

<?php
use Sermepa\Tpv\Tpv;
use Sermepa\Tpv\TpvException;

try {
    $key = 'sq7HjrUOBfKmC576ILgskD5srU870gJ7';

    $redsys = new Tpv();
    $redsys->setAmount(25.50)
        ->setOrder(date('YmdHis'))  // 20240215120000
        ->setMerchantcode('999008881')
        ->setCurrency('978')
        ->setTransactiontype('0')
        ->setTerminal('1')
        ->setMethod('C')
        ->setNotification('https://tusitio.com/notificacion')
        ->setUrlOk('https://tusitio.com/ok')
        ->setUrlKo('https://tusitio.com/ko')
        ->setVersion('HMAC_SHA256_V1')
        ->setTradeName('Mi Tienda')
        ->setTitular('Cliente Ejemplo')
        ->setProductDescription('Compra en Mi Tienda')
        ->setEnvironment('test');

    $signature = $redsys->generateMerchantSignature($key);
    $redsys->setMerchantSignature($signature);

    echo $redsys->createForm();

} catch (TpvException $e) {
    echo 'Error: ' . $e->getMessage();
}

Ejemplo Completo: Notificación (Callback)

<?php
use Sermepa\Tpv\Tpv;
use Sermepa\Tpv\TpvException;

try {
    $key = 'sq7HjrUOBfKmC576ILgskD5srU870gJ7';

    $redsys = new Tpv();

    // Decodificar parámetros
    $parameters = $redsys->getMerchantParameters($_POST['Ds_MerchantParameters']);

    // Obtener código de respuesta
    $DsResponse = (int) $parameters['Ds_Response'];
    $DsOrder = $parameters['Ds_Order'];

    // Validar firma y respuesta
    if ($redsys->check($key, $_POST)) {
        if ($DsResponse >= 0 && $DsResponse <= 99) {
            // Pago aprobado
            // Aquí: actualizar pedido en BDD, enviar confirmación, etc.
            error_log("Pago exitoso - Pedido: $DsOrder, Respuesta: $DsResponse");
        } else {
            // Pago denegado
            error_log("Pago denegado - Pedido: $DsOrder, Respuesta: $DsResponse");
        }
    } else {
        // Firma inválida - posible fraude
        error_log("Firma inválida - Pedido: $DsOrder");
    }

} catch (TpvException $e) {
    error_log('Error TPV: ' . $e->getMessage());
    http_response_code(500);
}

Changelog

Ver CHANGELOG.md para más detalles.

Licencia

MIT - Ver LICENSE.md


Contribuidores

Donación

¿Te gustaría apoyar este proyecto? ¡Gracias por tu aprecio!

Donar con PayPal

Support

¿Necesitas ayuda? Abre un issue