Estos últimos meses hemos estado integrando el TPV PC de Redsys en nuestro SaaS para la gestión de empresas de alquiler de vehículos.
Ya lo tenemos integrado con Stripe Terminal tanto para recibir cobros como para gestionar las fianzas. Queríamos añadir otro proveedor, el TPV PC de Redsys que lo facilitan los bancos en España.

Nuestro SaaS es una aplicación web. Además, nuestro entorno de desarrollo es con ordenadores Mac y Linux. En este artículo vamos a explicar algunos de los escollos a los que nos hemos enfrentado.
Comunicación con el dispositivo
La comunicación con el datáfono Verifone 400 se realiza a través de una DLL, dllTpvpcLatente.dll. Esto significa que este dispositivo sólo se pude usar desde un ordenador Windows con un driver que nos facilitaron y que se ha de instalar.
Implicaciones:
- El dispositivo sólo puede usarse en ordenadores con Windows
- El programa para la conexión se ha de programar en .Net u otra plataforma que permita generar ejecutables para windows. Para poderlo probar necesitábamos un ordenador con Windows.
- Desde el navegador no se puede ejecutar un programa que funciona en el ordenador del cliente. Necesitábamos implementar un servidor web o un servidor websockets para hacer esta comunicación.
Usando las funciones de la DLL
Para comunicar con el dispositivo, nos facilitaron esta web, https://www.bsdev.es/es/venta-presencial/tpv-pc/integracion-implantado-slim-pack/introduccion, que lo explica de forma detallada. También recibimos un documento PDF y la librería DLL. Es importante destacar que la DLL no se puede obtener desde el portal de Redsys. Te lo han de facilitar. Hay 2 versiones de la DLL, una para el entorno de integración y otra para el de producción.
La comunicación en sí, es sencilla. Defines la función, tal como está en la documentación y realizas la llamada. Ubicas la DLL en la carpeta raíz desde dónde ejecutas el programa ytienes la conexión.
[DllImport("dllTpvpcLatente.dll")]
private static extern int fnDllOperPinPad(
string cImporte,
string cFactura,
string cTipoOper,
StringBuilder cXMLResp,
int iTamMaxResp
);
StringBuilder respuestaXml = new StringBuilder(8192);
int result = fnDllOperPinPad(importe, factura, tipoOper, respuestaXml, 8192);El problema lo teníamos en cómo poder invocar este código desde nuestro programar. Teníamos que poderlo llamar desde JavaScript en el navegador.
Una característica importante es que la DLL es 32 bits. Has de compilar y ejecutar con el runtime de 32 bits. No hemos tenido que hacer nada especial en el código. Sólo usar el runtime tanto para construir, ejecutar como para compilar el EXE
Creando un programa nativo Windows
El primer hándicap era cómo crear un programa nativo en Windows. ¿Lo hacíamos en C#? ¿Adquiríamos Visual Studio? ¿Tenía sentido pagar una licencia cuando no íbamos a desarrollar nada más?
Descubrimos que se puede programar con .Net si necesidad de usar Visual Studio. Podíamos descargar el SDK y programar en Visual Studio Code. Incluso podíamos programar en MacOs o Linux pero para hacer funcionar la DLL teníamos que ejecutar el programa en un ordenador con Windows.
Nunca había trabajado con .NET y me ha parecido increíble. Tiene muchas cosas de serie. Puedes desarrollar con un editor de texto. Tiene muchas cosas de serie: Inyección de dependencias, UI con bindings, framework para crear aplicaciones web … Además de ser un lenguaje tipado.
Gracias a ChatGPT y otros LLMs, un programador con experiencia y base de arquitectura puede afrontar un proyecto como este. No puedo imaginar lo que me hubiera costado sin estas herramientas. Lectura de blogs, libros …
Comunicación entre el navegador y el programa
Lo primero que teníamos que implementar es la forma en la que pudiéramos El conectar nuestra plataforma y el programa que interactúa con el dispositivo.
El programa que interactúa con el dispositivo, además tendría que ofrecer una forma de poderse comunicar con el navegador. Nos decidimos por implementar servidor web que ofrecería una API para poder interactuar
| End Point | Funcionalidad |
| /api/payment | Realiza un pago |
| /api/preauthorization | Realiza una preautorización para bloquear el importe de una fianza |
| /api/refund | Realiza una devolución |
| /api/confirm-preauthorization | Realiza la confirmación de la preautorización para registrar el cobro de parte o todo el importe retenido |
Así que el programa debía permitir configurar el código de comercio, terminal, la clave de firma y arrancar un servidor web para realizar la comunicación.

El programa:
- Inicia una interfaz de usuario en Windows para realizar la configuración e iniciar el servicio
- Levanta un servidor web que atiende las peticiones
- Se conecta con el dispositivo
- Deja un registro de la operativa en un fichero de log.
Cada una de estas partes ha sido toda una experiencia y me encantaría entrar en detalle pero en este artículo quiero centrarme en los siguientes temas:
- Política CORS
- Conexión segura entre el navegador y el servidor web
Política CORS
Para poder conectar desde el navegador con el programa que se está ejecutando en el ordenador, es necesario especificar una política CORS. Nosotros definimos que permitiera conectar desde los subdominios de nuestra aplicación y durante la fase de desarrollo también permitir que se conectara desde un fichero. Así, pudimos asegurarnos que podríamos conectarnos si introducíamos en el navegador:
- http://localhost:8080
- https://localhost:8443
var builder = WebApplication.CreateBuilder();
// Preparar CORS
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
// Permitir orígenes dinámicos con un patrón personalizado
policy.SetIsOriginAllowed((origin) =>
{
// Verificar si el origen contiene .midominio.com
if (origin.Contains(".midominio.com"))
{
return true; // Permite el origen si es subdominio válido
}
// Permitir origen de file:// para pruebas locales
if (origin.StartsWith("file://") || origin == "null")
{
return true;
}
// Si no cumple con ninguno de los casos anteriores, rechazar
return false;
})
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.WebHost.UseKestrel(options =>
{
// HTTP
options.Listen(IPAddress.Loopback, 8080, listenOptions =>
{
});
});
var app = builder.Build();
// Usar CORS configurado por AddCors
app.UseCors();
// Agregar una ruta básica para responder a solicitudes GET
app.MapGet("/", () =>
{
return "¡Hola desde el servidor HTTPS con ASP.NET Core!";
});
app.MapPost("/ping", () =>
{
return "Pong";
});
_webHost = app.RunAsync();
await _webHost;
Conexión segura entre el navegador y el servidor web
Queríamos que la configuración entre el navegador y el servidor web fuera segura, con un certificado de seguridad. El problema es que el servidor web corre en localhost y no conseguimos obtener un certificado de seguridad en ningún portal de los que usamos habitualmente. No queríamos introducir la complejidad de tener que instalar Let’s Encrypt en los ordenadores de clientes. Teníamos que generar un certificado de seguridad propio.
Así que cremos un certificado con openssl y cuando fuimos a probarlo nos encontramos que el navegador lo detectaba como no seguro porque no estaba firmado por una Certificadora de Autoridad registrada. Necesitábamos:
- Crear una certificadora de autoridad
- Crear un certificado emitido por esta certificadora
- Instalar el certificado de la certificadora en el ordenador Windows.
Gracias a este artículo, https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/, pudimos crear una certificadora de autoridad y un certificado firmado por la misma.
Son estos 2 pasos, a partir de los cuales generaremos 2 archivos, myCA.key y myCA.pem. Este último lo usaremos para registrarlo en el ordenador Windows.
openssl genrsa -des3 -out myCA.key 2048
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.pem
Ahora hemos de instalar este certificado de autoridad en el ordenador en el que vamos a generar el certificado.
Podemos hacerlo en Mac desde la aplicación Acceso a llaveros

A continuación hacer doble click en indicar “confiar siempre”

Una vez instalado este certificado en el ordenador de desarrollo, nosotros lo hicimos en el Mac, hemos de generar un certificado firmado por esta autoridad, que es el que usaremos en el servidor web.
Crearemos el key para generar el certificado
openssl genrsa -out server.key 2048
Crearemos el csr para generar el certificado
openssl req -new -key server.key -out server.csr
Crearemos un fichero en la misma carpeta con nombre server.ext
authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = localhost
Por último, usaremos todos estos ficheros para generar nuestro certificado server.crt
openssl x509 -req -in server.csr -CA myCA.pem -CAkey myCA.key \ -CAcreateserial -out server.crt -days 825 -sha256 -extfile server.ext
Por último para poder usar el certificado en el servidor web del programa .Net hemos de generar el archivo server.pfx
openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt
Luego en el programa puedes configurarse el servidor para usar el certificado.
// Preparar el certificado
var certPath = "server.pfx";
var certPassword = "mi-password";
var certificate = new X509Certificate2(certPath, certPassword);
// Configurar Kestrel en .NET 8
builder.WebHost.UseKestrel(options =>
{
// HTTP
options.Listen(IPAddress.Loopback, 8080, listenOptions =>
{
});
// HTTPS
options.Listen(IPAddress.Loopback, 8443, listenOptions =>
{
listenOptions.UseHttps(certificate);
});
});Probando antes de integrar
Para poder probar el sistema antes de conectarlo con Mybooking creamos una UI HTML y JS con ayuda de https://v0.dev/. Queríamos algo rápido que permitiera probar todo el proceso desde el navegador antes de implementar la integración en nuestra solución porque queríamos centrarnos sólo en la operativa de pagos, devoluciones y preautorizaciones. Sin que estuviera vinculado con nuestro sistema y modelos.
