Webhooks Event-Driven: Tutorial Paso a Paso con Código Real | gigstack API 2026
Aprende a implementar webhooks event-driven con gigstack para recibir notificaciones en tiempo real sobre facturación. Tutorial completo con código Node.js, validación de firmas y manejo de errores.
¿Qué son los Webhooks Event-Driven?
Los webhooks son callbacks HTTP que permiten a tu aplicación recibir notificaciones automáticas cuando ocurren eventos específicos en gigstack, como la emisión de una factura, la cancelación de un CFDI o errores del SAT. En lugar de hacer polling constante a la API, gigstack te notifica en tiempo real cuando algo importante sucede.
Ventajas principales:
- Comunicación en tiempo real sin sobrecarga en tu servidor
- Reducción drástica de llamadas API innecesarias
- Arquitectura event-driven escalable y eficiente
- Sincronización automática entre gigstack y tu sistema
Arquitectura Event-Driven con gigstack
La API de gigstack 2026 utiliza un modelo de eventos basado en HTTP POST. Cuando ocurre un evento (factura emitida, timbrado exitoso, cancelación), gigstack envía una petición POST a la URL que hayas configurado con el payload del evento en formato JSON.
Eventos disponibles en 2026:
invoice.created- Nueva factura generadainvoice.stamped- Factura timbrada exitosamenteinvoice.cancelled- CFDI canceladoinvoice.failed- Error en el proceso de timbradopayment.received- Confirmación de pago registradosat.status_updated- Cambio en el estatus SAT de un CFDI
Paso 1: Configurar tu Endpoint de Webhooks
Primero, crea un endpoint en tu servidor que pueda recibir las peticiones POST de gigstack. Aquí un ejemplo con Node.js y Express:
const express = require('express');
const crypto = require('crypto');
const app = express();
// Middleware para parsear JSON
app.use(express.json());
// Endpoint para recibir webhooks de gigstack
app.post('/webhooks/gigstack', async (req, res) => {
try {
// Extraer headers importantes
const signature = req.headers['x-gigstack-signature'];
const webhookId = req.headers['x-gigstack-webhook-id'];
const timestamp = req.headers['x-gigstack-timestamp'];
// Payload del evento
const payload = req.body;
console.log('Evento recibido:', payload.event_type);
console.log('Datos:', payload.data);
// Validar firma (paso 2)
const isValid = validateSignature(payload, signature, timestamp);
if (!isValid) {
return res.status(401).json({ error: 'Firma inválida' });
}
// Procesar el evento según su tipo
await processEvent(payload);
// Responder rápidamente (< 5 segundos)
res.status(200).json({ received: true });
} catch (error) {
console.error('Error procesando webhook:', error);
res.status(500).json({ error: 'Error interno' });
}
});
app.listen(3000, () => {
console.log('Servidor de webhooks en puerto 3000');
});
Importante: Tu endpoint debe responder con un código 200 en menos de 5 segundos. Si la respuesta tarda más o falla, gigstack reintentará el envío automáticamente.
Paso 2: Validar la Firma del Webhook
Para garantizar que las peticiones provienen realmente de gigstack y no de un atacante, debes validar la firma criptográfica que gigstack incluye en cada webhook.
function validateSignature(payload, signature, timestamp) {
// Tu webhook secret (obtenlo desde el dashboard de gigstack)
const WEBHOOK_SECRET = process.env.GIGSTACK_WEBHOOK_SECRET;
// Verificar que el timestamp no sea muy antiguo (prevenir replay attacks)
const currentTime = Math.floor(Date.now() / 1000);
const timeDiff = currentTime - parseInt(timestamp);
if (timeDiff > 300) { // 5 minutos de tolerancia
console.error('Webhook expirado');
return false;
}
// Construir el payload firmado
const signedPayload = timestamp + '.' + JSON.stringify(payload);
// Calcular HMAC SHA-256
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(signedPayload)
.digest('hex');
// Comparación segura para prevenir timing attacks
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
El WEBHOOK_SECRET lo encuentras en tu dashboard de gigstack en la sección de configuración de webhooks. Guárdalo en variables de entorno, nunca lo expongas en tu código.
Paso 3: Procesar Eventos por Tipo
Una vez validado el webhook, procesa cada tipo de evento según tu lógica de negocio:
async function processEvent(payload) {
const { event_type, data } = payload;
switch (event_type) {
case 'invoice.stamped':
await handleInvoiceStamped(data);
break;
case 'invoice.cancelled':
await handleInvoiceCancelled(data);
break;
case 'invoice.failed':
await handleInvoiceFailed(data);
break;
case 'payment.received':
await handlePaymentReceived(data);
break;
default:
console.log('Evento no manejado:', event_type);
}
}
async function handleInvoiceStamped(data) {
const { invoice_id, cfdi_uuid, pdf_url, xml_url } = data;
console.log(`✅ Factura ${invoice_id} timbrada exitosamente`);
console.log(`UUID: ${cfdi_uuid}`);
// Actualizar tu base de datos
await db.invoices.update({
where: { gigstack_id: invoice_id },
data: {
status: 'timbrada',
uuid: cfdi_uuid,
pdf_url: pdf_url,
xml_url: xml_url,
stamped_at: new Date()
}
});
// Enviar email al cliente con la factura
await sendInvoiceEmail(invoice_id, pdf_url);
}
async function handleInvoiceFailed(data) {
const { invoice_id, error_code, error_message } = data;
console.error(`❌ Error timbrado factura ${invoice_id}`);
console.error(`Código SAT: ${error_code}`);
console.error(`Mensaje: ${error_message}`);
// Notificar al equipo
await notifyTeam({
type: 'invoice_error',
invoice_id,
error: error_message
});
// Actualizar status
await db.invoices.update({
where: { gigstack_id: invoice_id },
data: {
status: 'error',
error_code,
error_message
}
});
}
Paso 4: Configurar Webhooks en gigstack Dashboard
Para activar los webhooks en gigstack 2026:
- Accede a tu dashboard en app.gigstack.pro
- Ve a Configuración → Webhooks
- Clic en “Agregar Webhook”
- Ingresa tu URL endpoint (debe ser HTTPS en producción):
https://tuapp.com/webhooks/gigstack - Selecciona los eventos que deseas recibir
- Guarda el Webhook Secret que se genera automáticamente
- Activa el webhook y haz clic en “Enviar evento de prueba”
Tip: Durante desarrollo, usa herramientas como ngrok o webhook.site para exponer tu localhost y recibir webhooks de prueba.
Paso 5: Implementar Retry Logic
gigstack reintenta automáticamente los webhooks fallidos, pero tu aplicación debe ser idempotente para manejar duplicados:
// Tabla para tracking de webhooks procesados
const processedWebhooks = new Set();
app.post('/webhooks/gigstack', async (req, res) => {
const webhookId = req.headers['x-gigstack-webhook-id'];
// Verificar si ya procesamos este webhook
if (processedWebhooks.has(webhookId)) {
console.log('Webhook duplicado, ignorando...');
return res.status(200).json({ received: true });
}
try {
// Validar y procesar
await validateAndProcess(req);
// Marcar como procesado
processedWebhooks.add(webhookId);
res.status(200).json({ received: true });
} catch (error) {
// No marcar como procesado si falló
res.status(500).json({ error: error.message });
}
});
En producción, usa una base de datos o Redis para persistir los IDs de webhooks procesados, no un Set en memoria.
Testing en Sandbox 2026
gigstack ofrece un ambiente sandbox completo para probar webhooks sin afectar datos reales:
// Configurar cliente para sandbox
const GigstackClient = require('@gigstack/sdk-node');
const client = new GigstackClient({
apiKey: process.env.GIGSTACK_SANDBOX_KEY,
environment: 'sandbox', // Usar sandbox para testing
webhookSecret: process.env.GIGSTACK_WEBHOOK_SECRET_SANDBOX
});
// Crear factura de prueba que disparará webhook
const testInvoice = await client.invoices.create({
customer: {
rfc: 'XAXX010101000',
name: 'Cliente Prueba',
email: 'test@example.com'
},
items: [{
description: 'Producto de prueba',
unit_price: 100,
quantity: 1
}]
});
console.log('Factura de prueba creada, webhook será enviado...');
FAQ Técnica
1. ¿Qué hago si mi endpoint no recibe los webhooks?
Verificaciones:
- Confirma que tu URL es accesible públicamente (usa
curlpara probar) - Verifica que aceptas POST requests con Content-Type: application/json
- Revisa logs de firewall o WAF que puedan estar bloqueando gigstack
- En el dashboard de gigstack, revisa el Log de Webhooks para ver intentos y errores
2. ¿Cuántas veces gigstack reintenta un webhook fallido?
gigstack reintenta hasta 5 veces con backoff exponencial: 1min, 5min, 15min, 1hr, 6hrs. Después de 5 intentos fallidos, el webhook se marca como “failed” y puedes revivirlo manualmente desde el dashboard.
3. ¿Los webhooks incluyen datos sensibles del SAT?
Los webhooks NO incluyen el XML completo del SAT. Incluyen metadatos clave (UUID, totales, status) y URLs firmadas temporalmente para descargar PDF/XML. Las URLs expiran en 24 horas por seguridad.
4. ¿Cómo manejo webhooks duplicados o fuera de orden?
Implementa lógica idempotente usando el x-gigstack-webhook-id como clave única. Además, cada evento incluye un timestamp y un sequence_number para ordenar eventos relacionados cronológicamente.
Recursos Adicionales
- Documentación oficial: docs.gigstack.io/webhooks
- SDK Node.js: @gigstack/sdk-node (actualizado para 2026)
- Referencia de eventos: docs.gigstack.io/api/events
- Ejemplos de código: github.com/gigstack/webhook-examples
Con esta arquitectura event-driven, tu integración con gigstack será robusta, escalable y en tiempo real. Los webhooks eliminan la necesidad de polling, reducen latencia y mejoran significativamente la experiencia de usuario al mantener tus sistemas sincronizados automáticamente. 🚀