Criterio 01
Datos de creación exclusivos del firmante
Código OTP de 6 dígitos enviado únicamente al correo del firmante. Validado por HMAC-SHA256 con una clave del servidor que el cliente no conoce.
Documentación
Validador de certificados, descripción del paquete probatorio, mapeo al Decreto 2364 y referencia de la API.
Sección 01
Pegá el hash de un certificado emitido por easyFirma para consultar sus datos. Opcionalmente, subí el PDF original para verificar que su contenido no haya sido modificado desde la firma.
Esperando consulta
Cargá un hash o el demo para verificar un certificado.
Consultando registro…
Error
Sin registro
El hash ingresado no está en el registro de certificados. Verificá que esté escrito correctamente.
Certificado válido
Integridad confirmada
Sección 02
Cada firma genera un registro estructurado y un PDF conservado. Esto es lo que un perito o abogado puede pedirnos para defender la firma en juicio.
Estructura del certificado
{
"hash": "C0577351D464D260A8A24CAB...",
"pdfHash": "5A4B3C2D1E9F8A...",
"nombre": "Gabriel Valenzuela",
"cedula": "1018273645",
"email": "gabriel@ejemplo.co",
"ip": "186.29.32.12",
"timestamp": "2026-05-21T15:42:08.391Z",
"confirmation": "ACEPTO",
"otpVerified": true,
"otpTimestamp": 1747867200000
}
Hash del documento
SHA-256 sobre los bytes del PDF firmado. No sobre la URL. Cualquier modificación al documento, por mínima que sea, invalida el hash.
Hash compuesto
SHA-256 sobre nombre · cédula · email · ip · timestamp · pdfHash. Es el identificador único del registro.
IP de origen
Capturada en el servidor a partir de cabeceras de conexión. No se acepta IP enviada por el cliente.
Voluntad expresa
Texto que el firmante tipea manualmente para confirmar (palabra clave o nombre). Capturado tal cual.
Código OTP
6 dígitos enviados al correo, validados con clave del servidor, expiración a 10 minutos, marcados como usados al consumirse.
Sección 03
El Decreto 2364 de 2012 define cuatro criterios de confiabilidad para una firma electrónica verificable. easyFirma cumple cada uno de la siguiente manera.
Criterio 01
Código OTP de 6 dígitos enviado únicamente al correo del firmante. Validado por HMAC-SHA256 con una clave del servidor que el cliente no conoce.
Criterio 02
El OTP se tipea manualmente en pantalla. Sin magic link. Sin auto-firma. Los previewers de correo no pueden completar el flujo. El código es de uso único.
Criterio 03
Hash SHA-256 calculado sobre los bytes del PDF firmado. Conservación del archivo exacto indexado por su hash. Si cambia un solo byte, el hash deja de coincidir.
Criterio 04
El registro completo (firmante, IP, timestamp, voluntad expresa, hash del PDF) lleva su propio hash compuesto. Modificar el registro lo invalida.
Sección 04
Flujo seguro de tres pasos: creación de una sesión de firma efímera desde tu backend, redirección del firmante usando un token seguro de un solo uso, y recepción del webhook con el certificado firmado.
Desde tu servidor, genera un token efímero de firma enviando una petición POST con tu clientApiKey. Nunca expongas tu API Key ni secretos en el navegador del firmante.
Petición HTTP (POST /sessions)
POST /.netlify/functions/sessions HTTP/1.1 Authorization: Bearer ef_live_k_sura_123... Content-Type: application/json { "pdfUrl": "https://sura.com.co/polizas/contrato.pdf", "redirectUrl": "https://sura.com.co/firma-exitosa", "signerHints": { "nombre": "Gabriel Valenzuela", "email": "gabriel@ejemplo.co" }, "metadata": { "polizaId": "POL-2026-09" } }
Respuesta (200 OK)
{
"ok": true,
"sessionToken": "ef_sess_abc123...",
"firmUrl": "https://easyfirma.digital/firma.html?token=ef_sess_abc123...",
"expiresAt": "2026-05-21T22:30:00.000Z"
}
| Campo | Descripción | Tipo |
|---|---|---|
| pdfUrl | URL pública y directa del archivo PDF a firmar. | Requerido |
| redirectUrl | URL a la cual redirigir al firmante tras firmar con éxito. | Opcional |
| signerHints.nombre | Nombre completo para pre-llenar el formulario. | Opcional |
| signerHints.email | Correo para pre-llenar y enviar el código OTP. | Opcional |
| metadata | Objeto JSON libre para asociar identificadores internos tuyos. | Opcional |
Redirige a tu usuario a la firmUrl recibida. El firmante visualizará la interfaz con el branding de tu marca configurado (nombre, logo y colores), sin exponer credenciales ni configuraciones privadas.
https://easyfirma.digital/firma.html?token=ef_sess_abc123...
Nota: Por seguridad, cada enlace de firma es de un solo uso y expira automáticamente a las 2 horas.
Al completarse la firma, easyFirma envía un POST JSON a tu webhookUrl configurada. Si tienes un webhookSecret configurado, el cuerpo va firmado con HMAC-SHA256 en el encabezado X-EasyFirma-Signature.
Cuerpo del webhook
{
"event": "signature.completed",
"timestamp": 1747867200000,
"data": {
"transactionId": "C0577351...",
"certificateHash": "C0577351...",
"pdfHash": "5A4B3C2D...",
"clientId": "sura-001",
"metadata": { "polizaId": "POL-2026-09" },
"firmante": {
"nombre": "Gabriel Valenzuela",
"cedula": "1018273645",
"email": "gabriel@ejemplo.co",
"ip": "186.29.32.12",
"declaracion": "APROBAR",
"timestamp": "2026-05-21T15:42:08.391Z"
}
}
}
Validar la firma (Node.js)
const crypto = require('crypto'); app.post('/webhook', (req, res) => { const sig = req.headers['x-easyfirma-signature']; const secret = process.env.EASYFIRMA_WEBHOOK_SECRET; // Calcular HMAC usando el body en bruto (raw body) const expected = crypto .createHmac('sha256', secret) .update(req.rawBody) .digest('hex'); // Comparación en tiempo constante para evitar ataques de timing const match = crypto.timingSafeEqual( Buffer.from(sig, 'hex'), Buffer.from(expected, 'hex') ); if (match) { res.sendStatus(200); } else { res.sendStatus(401); } });
GET por hash y ID de cliente. Retorna el log público de transparencia sin datos de carácter personal (PII). Cumple 100% con Ley 1581 (Habeas Data).
curl -X GET \ "https://easyfirma.digital/.netlify/functions/certs?hash=C0577351...&clientId=sura-001"