Webhook para Fintechs
Implementa la validación técnica y de seguridad de mensajes recibidos por webhook: autenticidad, integridad, antireplay, idempotencia y trazabilidad.
Voultech puede entregar eventos a tu integración vía Webhook o vía Azure Service Bus — ambos canales entregan los mismos eventos. Esta guía describe cómo implementar el receptor webhook y validar correctamente cada mensaje para garantizar autenticidad, integridad, antireplay, idempotencia y trazabilidad.
Si prefieres consumir eventos en modo pull (sin exponer un endpoint público), consulta la guía de Azure Service Bus.
Objetivos de seguridad
| Objetivo | Descripción |
|---|---|
| Autenticidad | Confirmar que el emisor del webhook es Voultech. |
| Integridad | Confirmar que el payload no fue modificado en tránsito. |
| Antireplay | Evitar reenvíos maliciosos del mismo webhook. |
| Idempotencia | Evitar efectos duplicados ante reintentos (normales en webhooks). |
| Trazabilidad | Auditar qué se recibió, cuándo y cómo se procesó. |
Requisitos de transporte
- HTTPS obligatorio (TLS 1.2+).
- Método:
POST - Content-Type:
application/json - Timeouts: responde rápido (ideal < 2–5 s) y procesa asincrónicamente si el negocio lo requiere.
- Respuesta:
2xxsolo si fue aceptado y validado. Usa4xxpara errores del request y5xxpara fallas internas.
Cabeceras del mensaje
Cada webhook enviado por Voultech incluye las siguientes cabeceras:
| Cabecera | Descripción |
|---|---|
X-Timestamp | Epoch en segundos (UTC). Usado para antireplay y como parte de la firma. |
X-Idempotency-Key | Clave idempotente del envío. |
X-Signature | Firma HMAC-SHA256 del payload, con el prefijo sha256=. |
Ejemplo:
X-Timestamp: 1730000000
X-Idempotency-Key: 8b5c1a2e-...
X-Signature: sha256=BASE64_HMAC_SHA256
Validación paso a paso
1. Validación básica del request
- Verificar que el método es
POST. - Verificar el
Content-Typeesperado (application/json). - Parsear el JSON y validar el esquema mínimo.
2. Validar autenticidad e integridad (firma)
Se usa HMAC-SHA256 con secreto compartido. Voultech calcula la firma sobre el body crudo y la codifica en Base64. Tu integración debe recalcular y comparar en tiempo constante.
Construcción de la firma (exacto):
signing_string = X-Timestamp + "." + raw_body
signature = base64(hmac_sha256(secret, signing_string))
Formato esperado del header X-Signature:
X-Signature: sha256=<signature_base64>
La firma debe calcularse sobre el body crudo (raw body), nunca sobre el JSON reserializado. La comparación debe realizarse siempre en tiempo constante para evitar ataques de timing.
3. Validación antireplay (timestamp + ventana)
- Verificar que
X-Timestampesté dentro de la ventana tolerable. - La tolerancia configurada es
WebhookSignature:MaxSkewSeconds(por defecto 300 segundos). - Si el timestamp está fuera de la ventana: rechazar con
401.
4. Validación de idempotencia (X-Idempotency-Key)
X-Idempotency-Key)- Extraer
X-Idempotency-Key. - Persistirlo con una restricción
UNIQUEen tu base de datos. - Si el evento ya existe: responder
200/2xxy no reprocesar (o reprocesar solo bajo reglas claras si quedó en estadofailed).
Códigos HTTP de respuesta
| Caso | Código |
|---|---|
| Firma inválida / timestamp inválido | 401 o 403 |
| JSON inválido / esquema inválido | 400 |
| Evento duplicado (idempotencia) | 200 (recomendado para no incentivar reintentos) |
| Falla interna temporal | 500 (fuerza reintento por parte de Voultech) |
Ejemplo de implementación en C#
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Mvc;
static string ComputeHmacSha256Base64(string secret, string data)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(data)));
}
static bool ConstantTimeEqualsBase64(string a, string b)
{
try
{
var ba = Convert.FromBase64String(a);
var bb = Convert.FromBase64String(b);
return CryptographicOperations.FixedTimeEquals(ba, bb);
}
catch (FormatException)
{
return false;
}
}
app.MapPost("/webhook", async ([FromServices] IConfiguration config, HttpRequest request) =>
{
var timestampHeader = request.Headers["X-Timestamp"].ToString();
var signatureHeader = request.Headers["X-Signature"].ToString();
// 1) Validación de headers obligatorios
if (string.IsNullOrWhiteSpace(timestampHeader) || string.IsNullOrWhiteSpace(signatureHeader))
return Results.Unauthorized();
// 2) Parse de timestamp
if (!long.TryParse(timestampHeader, out var ts))
return Results.Unauthorized();
// 3) Validación antireplay (skew)
var maxSkewSeconds = config.GetValue<int?>("WebhookSignature:MaxSkewSeconds") ?? 300;
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
if (Math.Abs(now - ts) > maxSkewSeconds)
return Results.Unauthorized();
// 4) Obtener secret
var secret = config["WebhookSignature:Secret"];
if (string.IsNullOrWhiteSpace(secret))
return Results.Problem("Missing WebhookSignature:Secret", statusCode: 500);
// 5) Normalizar firma (remover prefijo sha256= si viene)
var receivedSignature = signatureHeader.StartsWith("sha256=", StringComparison.OrdinalIgnoreCase)
? signatureHeader["sha256=".Length..]
: signatureHeader;
// 6) Leer raw body y recalcular firma
using var reader = new StreamReader(request.Body);
var rawBody = await reader.ReadToEndAsync();
var signingString = $"{timestampHeader}.{rawBody}";
var expectedSignature = ComputeHmacSha256Base64(secret, signingString);
// 7) Comparación en tiempo constante
if (!ConstantTimeEqualsBase64(expectedSignature, receivedSignature))
return Results.Unauthorized();
// OK: el webhook es auténtico e íntegro
return Results.Ok(new { status = "validated" });
});Ejemplo de mensaje JSON
El mensaje JSON enviado por Voultech sigue la misma estructura de eventos del sistema. Ejemplo para el topic KYCVALIDATION:
{
"Topic": "KYCVALIDATION",
"Date": "2026-01-21 18:59:00",
"Code": "TEST_FINTECH",
"Fintech": "TEST_FINTECH",
"Detail": {
"Information": "Transaction validated successfully",
"UserId": "12345678",
"State": "APPROVED",
"documentType": "DNI",
"documentNumber": "12345678",
"riskScore": 12,
"provider": "Sumsub",
"country": "CL"
}
}El campo
Topicidentifica el tipo de evento. Los topics disponibles son los mismos que se describen en la sección Sistema de Eventos (MOVBANCO, REVERSAMOVBANCO, MOVSHINKANSEN, KYCVALIDATION).
Updated 4 months ago
