BeeL.es
Producto
Precio
Precio
← Blog
Desarrollo8 min de lectura

Webhooks de Facturación: Eventos en Tiempo Real con Verificación HMAC

Recibe eventos de facturación en tiempo real: facturas emitidas, pagadas, estado VeriFactu. Verificación HMAC-SHA256 integrada en el SDK para seguridad enterprise.

09 Abril 2026•
Roger Massana
Roger Massana

#Polling no escala. Los webhooks sí.

El patrón más común para saber si algo cambió en un sistema externo es hacer polling: preguntar cada X segundos “¿hay algo nuevo?”. Funciona, pero tiene problemas reales:

  • Latencia: tus datos están desactualizados hasta el próximo poll
  • Coste: miles de peticiones vacías que devuelven “nada nuevo”
  • Rate limits: cuantas más peticiones, más cerca del límite

Los webhooks invierten el modelo: BeeL te avisa a ti cuando algo ocurre. Factura emitida, factura pagada, estado VeriFactu actualizado — tu servidor recibe un evento en tiempo real.

La API de BeeL soporta webhooks con verificación HMAC-SHA256 incluida en el SDK de TypeScript. Seguridad enterprise sin implementar criptografía.


#Cómo funcionan los webhooks de BeeL

  1. Configuras una URL de tu servidor (endpoint) en el panel de BeeL
  2. BeeL te asigna un webhook secret (whsec_...)
  3. Cuando ocurre un evento, BeeL envía un POST a tu URL con:
    • Body: JSON con los datos del evento
    • Header BeeL-Signature: firma HMAC-SHA256 para verificar autenticidad

#Tipos de eventos

EventoCuándo se dispara
invoice.createdSe crea un borrador de factura
invoice.issuedSe emite una factura (número asignado + VeriFactu)
invoice.paidSe marca una factura como pagada
invoice.sentSe envía una factura por email
invoice.voidedSe anula una factura emitida
verifactu.status_updatedCambia el estado de registro VeriFactu

El evento verifactu.status_updated es especialmente útil: te permite saber cuándo la AEAT ha procesado y aceptado (o rechazado) el registro de una factura.


#Implementación con Express.js y el SDK

import express from 'express';
import { WebhookVerifier } from '@beel_es/sdk';
 
const app = express();
const verifier = new WebhookVerifier(process.env.BEEL_WEBHOOK_SECRET!);
 
// IMPORTANTE: express.raw() para recibir el body sin parsear
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const event = verifier.verify(
      req.body,
      req.headers['beel-signature'] as string
    );
 
    switch (event.type) {
      case 'invoice.issued':
        console.log(`Factura emitida: ${event.data.invoice_number}`);
        // Actualizar tu sistema: CRM, contabilidad, notificaciones...
        break;
 
      case 'invoice.paid':
        console.log(`Factura pagada: ${event.data.invoice_number}`);
        // Marcar como cobrada en tu sistema
        break;
 
      case 'verifactu.status_updated':
        console.log(`VeriFactu: ${event.data.status}`);
        // Registrar el estado de cumplimiento
        break;
 
      default:
        console.log(`Evento no gestionado: ${event.type}`);
    }
 
    res.json({ received: true });
  } catch (err) {
    console.error('Webhook inválido:', err);
    res.status(400).json({ error: 'Invalid signature' });
  }
});
 
app.listen(3000);

⚠️Body sin parsear

El verificador necesita el body raw (sin parsear por JSON middleware). Si usas express.json() globalmente, excluye la ruta del webhook o usa express.raw() específicamente.


#Cómo funciona la verificación HMAC-SHA256

La verificación protege contra dos amenazas:

  1. Suplantación: alguien envía eventos falsos a tu endpoint
  2. Replay attacks: alguien reenvía un evento legítimo antiguo

#El proceso

El header BeeL-Signature tiene el formato:

BeeL-Signature: t=1712678400,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
  • t = timestamp Unix (segundos) del momento del envío
  • v1 = firma HMAC-SHA256

El SDK verifica:

  1. Parsear el header para extraer timestamp y firma
  2. Calcular HMAC-SHA256(secret, timestamp + "." + body)
  3. Comparar la firma calculada con v1 usando comparación en tiempo constante (previene timing attacks)
  4. Verificar frescura: el timestamp no debe tener más de 5 minutos de antigüedad (configurable)
// Internamente, el SDK hace esto:
const expectedSignature = crypto
  .createHmac('sha256', secret)
  .update(`${timestamp}.${rawBody}`)
  .digest('hex');
 
// Comparación en tiempo constante — NO usar ===
crypto.timingSafeEqual(
  Buffer.from(expectedSignature),
  Buffer.from(receivedSignature)
);

ℹ️¿Por qué comparación en tiempo constante?

Si usas ===, el tiempo de respuesta varía según cuántos caracteres coinciden. Un atacante puede inferir la firma correcta carácter a carácter midiendo tiempos de respuesta. timingSafeEqual tarda lo mismo independientemente de cuántos caracteres coincidan.


#Verificación manual (sin SDK)

Si no usas Node.js, puedes implementar la verificación en cualquier lenguaje:

# Python
import hmac
import hashlib
import time
 
def verify_webhook(body: bytes, signature_header: str, secret: str):
    # 1. Parsear header
    parts = dict(p.split('=', 1) for p in signature_header.split(','))
    timestamp = parts['t']
    signature = parts['v1']
 
    # 2. Verificar frescura (5 minutos)
    if abs(time.time() - int(timestamp)) > 300:
        raise ValueError('Timestamp too old')
 
    # 3. Calcular firma esperada
    payload = f"{timestamp}.{body.decode()}"
    expected = hmac.new(
        secret.encode(), payload.encode(), hashlib.sha256
    ).hexdigest()
 
    # 4. Comparar en tiempo constante
    if not hmac.compare_digest(expected, signature):
        raise ValueError('Invalid signature')

#Reintentos y manejo de fallos

Si tu servidor no responde (timeout o error 5xx), BeeL reintenta con backoff exponencial:

IntentoDelay
1Inmediato
21 minuto
35 minutos
430 minutos
52 horas

Puedes ver los logs de entrega en tu panel de BeeL para diagnosticar problemas.

Buenas prácticas:

  • Responde con 200 lo antes posible — procesa el evento de forma asíncrona si es pesado
  • Implementa idempotencia: guarda el event.id y descarta duplicados
  • No confíes en el orden de llegada — los eventos pueden llegar desordenados

#Ejemplo: sincronizar con un sistema de contabilidad

// Webhook handler que sincroniza facturas pagadas con contabilidad
case 'invoice.paid':
  const invoice = event.data;
 
  // Registrar en el sistema contable
  await accounting.createEntry({
    date: invoice.payment_date,
    description: `Cobro factura ${invoice.invoice_number}`,
    debit: { account: '570', amount: invoice.total },  // Caja
    credit: { account: '430', amount: invoice.total },  // Clientes
  });
 
  // Notificar al equipo
  await slack.send('#contabilidad',
    `Factura ${invoice.invoice_number} cobrada: ${invoice.total}€`
  );
  break;

#Preguntas frecuentes

#¿Qué eventos puedo recibir por webhook?

Los principales: invoice.issued, invoice.paid, invoice.voided, invoice.sent, invoice.created y verifactu.status_updated. Puedes filtrar qué eventos recibes al configurar el webhook.

#¿Qué pasa si mi servidor no responde?

BeeL reintenta con backoff exponencial hasta 5 veces en un período de ~3 horas. Los logs de entrega están disponibles en tu panel para diagnosticar problemas.

#¿Por qué es importante verificar la firma HMAC?

Sin verificación, cualquiera que conozca tu URL de webhook podría enviar eventos falsos — por ejemplo, marcar facturas como pagadas sin que realmente lo estén. La verificación HMAC garantiza que solo BeeL puede enviar eventos válidos.

#¿Puedo usar webhooks sin el SDK?

Sí. El SDK simplifica la verificación con WebhookVerifier, pero puedes implementar HMAC-SHA256 manualmente en cualquier lenguaje. El artículo incluye un ejemplo en Python.

#¿Los webhooks funcionan en desarrollo local?

Sí, usando herramientas como ngrok o localtunnel para exponer tu servidor local a internet. Configura la URL temporal de ngrok como endpoint en BeeL.


¿Listo para recibir eventos en tiempo real? Configura tu primer webhook en el panel de BeeL, instala el SDK (código fuente en GitHub) y empieza a procesar eventos. La documentación tiene la referencia completa de tipos de eventos, y en la página de SDKs encontrarás quickstarts para TypeScript, Java y Python. También puedes procesar webhooks con n8n sin escribir código.

¿Te ha resultado útil? Compártelo con otros autónomos

Compartir:

¿Listo para simplificar tu facturación?

Únete a BeeL.es y cumple con Verifactu sin complicaciones

7 días gratis

← Ver todos los artículos del blog
BeeL.es

Nuestro mejor cliente pasa 47 segundos al mes en BeeL. Ese es el objetivo.

Producto

  • Blog
  • API
  • Docs API
  • Stripe
  • Demo gestorías
  • Roadmap
  • Status

Comparaciones

  • Comparar software
  • vs Holded
  • vs Quipu
  • vs Contasimple
  • vs STEL Order
  • vs A3Factura
  • Ver todas →

Verifactu

  • ¿Qué es Verifactu?
  • Fechas y plazos
  • Guía para autónomos
  • Multas y sanciones
  • Artículos sobre Verifactu →
  • Por ciudades →

Comunidad

  • LinkedIn
  • Instagram
  • TikTok
  • YouTube

Legal

  • Privacidad
  • Cookies
  • Términos
  • Cancelación
  • Declaración Responsable

© 2026 BeeL.es - Hecho con ❤️ para autónomos como tú

BeeL.es - Platja d'Aro, Girona, España•hola@beel.es•WhatsApp