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:
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 CFDIPrimero, 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.
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.
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
}
});
}
Para activar los webhooks en gigstack 2026:
https://tuapp.com/webhooks/gigstackTip: Durante desarrollo, usa herramientas como ngrok o webhook.site para exponer tu localhost y recibir webhooks de prueba.
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.
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...');
Verificaciones:
curl para probar)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.
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.
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.
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. 🚀
Para activar los webhooks en gigstack 2026:
https://tuapp.com/webhooks/gigstackTip: Durante desarrollo, usa herramientas como ngrok o webhook.site para exponer tu localhost y recibir webhooks de prueba.
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.
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...');
Verificaciones:
curl para probar)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.
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.
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.
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. 🚀
