Redsys - Biblioteca PHP para Pasarela de Pagos
March 7, 2026 · View on GitHub
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
| Entorno | Descripción |
|---|---|
test | Pruebas (SIS Sandbox) |
live | Producción |
restTest | API REST Pruebas |
restLive | API REST Producción |
insiteSandbox | InSite Pruebas (JS + REST) |
insiteLive | InSite Producción (JS + REST) |
insiteRestSandbox | InSite REST Pruebas (solo pago) |
insiteRestLive | InSite REST Producción (solo pago) |
Métodos de Pago
| Código | Descripción |
|---|---|
C o T | Tarjeta |
R | Transferencia |
D | Domiciliación |
z | Bizum |
p | PayPal |
N | Masterpass |
xpay | GooglePay / ApplePay |
Tipos de Transacción
| Código | Descripción |
|---|---|
0 | Autorización |
1 | Preautorización |
2 | Confirmación de preautorización |
3 | Anulación de preautorización |
4 | Devolución |
5 | Cancelación |
7 | Preautorización extendida |
8 | Confirmación preautorización extendida |
9 | Baja de preautorización extendida |
Códigos de Respuesta
El banco devuelve un código en Ds_Response. Los principales:
| Código | Significado |
|---|---|
0000 a 0099 | Pago aprobado |
0100 a 0199 | Operatoria OK, verificación CVV obligatoria |
0200 | Error de formato |
0201 | Error de firma |
0204 | Error de datos |
0209 | Error de tajeta |
0214 | Fecha de caducidad errónea |
0215 | Error en importe mínimo (no usado) |
0290 | Tarjeta no autorizada |
0401 | Error en posición de tarjeta |
0404 | Error de configuración de comercio |
0501 | Operaciones pendientes |
0904 | Comercio no operativo |
0912 | Emisor no disponible |
9912 | Emisor no disponible |
9913 | Error en comunicación |
9914 | Fallo al conectar con CA |
9919 | Error de cryptograma |
9929 | Error de deslinde |
9932 | Error de bin |
9933 | Error de BS. Cambio de dinámico a estático |
9934 | Error de BS. Cambio de estático a dinámico |
9951 | Operación de ingreso OK |
9952 | Operación de ingreso NO OK |
9953 | Devolución OK |
9954 | Devolución NO OK |
9955 | Anulación OK |
9956 | Anulación NO OK |
9957 | Ajuste OK |
9958 | Ajuste NO OK |
9961 | Error en cierre batch |
9962 | Error en apertura batch |
9963 | Error de operativa |
9992 | Petición cancelada |
9993 | Operatoria abandonada por el usuario |
9995 | Operatoria abandonada - tiempo excedido |
9996 | Error de conexión |
9997 | Error de timeout |
9998 | Error de validación |
9999 | Error general |
Nota: Para pagos exitosos, el código debe estar entre
0000y0099. 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
- Generar formulario InSite - Renderiza el iframe en tu página
- Usuario completa pago - Introduce datos en el iframe de Redsys
- Obtener ID de operación - Redsys retorna un
idOper(válido por 30 minutos) - Ejecutar pago - Envía el
idOpermediante 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ó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ámetro | Obligatorio | Descripción |
|---|---|---|
id / $containerId | Sí | ID del contenedor div |
fuc / merchantCode | Sí | Código de comercio (FUC) |
terminal | Sí | Número de terminal |
order | Sí | Número de pedido (4-12 caracteres) |
styleButton | No | CSS para el botón de pago |
styleBody | No | CSS para el cuerpo del formulario |
styleBox | No | CSS para la caja de datos |
styleBoxText | No | CSS para el texto de los inputs |
buttonValue | No | Texto del botón (HTML encoded) |
idiomaInsite | No | Código de idioma (ver tabla) |
mostrarLogoInsite | No | Mostrar logo de entidad (default: true) |
estiloReducidoInsite | No | Usar estilo reducido (default: false) |
estiloInsite | No | 'inline' o 'twoRows' (default: 'inline') |
Catálogo de Idiomas InSite
| Idioma | Código SIS | ISO 639-1 |
|---|---|---|
| Español | 1 | ES |
| Inglés | 2 | EN |
| Catalán | 3 | CA |
| Francés | 4 | FR |
| Alemán | 5 | DE |
| Italiano | 7 | IT |
| Portugués | 9 | PT |
| ... | ... | ... |
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ódigo | Descripción |
|---|---|
| msg1 | Ha de rellenar los datos de la tarjeta |
| msg2 | La tarjeta es obligatoria |
| msg3 | La tarjeta ha de ser numérica |
| msg15 | La longitud de la tarjeta no es correcta |
| msg16 | Debe introducir un número de tarjeta válido |
| msg17 | Validación incorrecta por parte del comercio |
| msg18 | Error 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étodo | Descripció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ón | Descripción |
|---|---|
2 | Redsys Classic |
3 | Redsys 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ódigo | Idioma |
|---|---|
| 001 | Castellano |
| 002 | Inglés |
| 003 | Catalán |
| 004 | Francés |
| 005 | Alemán |
| 006 | Holandés |
| 007 | Italiano |
| 008 | Sueco |
| 009 | Portugués |
| 010 | Valenciano |
| 011 | Polaco |
| 012 | Gallego |
| 013 | Euskera |
API Reference
Métodos de Configuración
| Método | Descripción | Requerido |
|---|---|---|
setAmount(float) | Importe (se convierte a céntimos) | Sí |
setOrder(string) | Número de pedido (4-12 caracteres, primeros 4 numéricos) | Sí |
setMerchantcode(string) | Código de comercio (FUC) | Sí |
setCurrency(string) | Código de moneda ISO | Sí |
setTransactiontype(string) | Tipo de transacción | Sí |
setTerminal(string) | Número de terminal | Sí |
setMethod(string) | Método de pago | No |
setNotification(string) | URL de notificación (callback) | Recomendado |
setUrlOk(string) | URL si pago exitoso | Recomendado |
setUrlKo(string) | URL si pago fallido | Recomendado |
setEnvironment(string) | Entorno de conexión | No |
setVersion(string) | Versión de firma | No |
setTradeName(string) | Nombre del comercio | No |
setTitular(string) | Titular del pago | No |
setProductDescription(string) | Descripción del producto | No |
Métodos de Firma y Envío
| Método | Descripció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étodo | Descripción |
|---|---|
check(string $key, array $postData) | Valida firma de respuesta del banco |
getMerchantParameters(string) | Decodifica Ds_MerchantParameters |
Métodos InSite
| Método | Descripció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ámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
$containerId | string | No | ID del contenedor div (default: 'card-form') |
$buttonStyle | string | No | CSS para el botón de pago |
$bodyStyle | string | No | CSS para el cuerpo del formulario |
$boxStyle | string | No | CSS para la caja de datos |
$inputStyle | string | No | CSS para los inputs |
$buttonText | string | No | Texto del botón (HTML encoded) |
$language | string | No | Código de idioma (default: 'ES') |
$showLogo | bool | No | Mostrar logo de entidad (default: true) |
$reducedStyle | bool | No | Usar estilo reducido (default: false) |
$insiteStyle | string | No | 'inline' o 'twoRows' (default: 'inline') |
Métodos Auxiliares
| Método | Descripció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
- Eduardo D - Autor original
- jaumecornado - Redirección automática
- markitosgv - Validación de respuesta
Donación
¿Te gustaría apoyar este proyecto? ¡Gracias por tu aprecio!
Support
¿Necesitas ayuda? Abre un issue
