Guías
February 27, 2026

Webhooks Event-Driven: Tutorial Paso a Paso con Código Real | gigstack API 2026

Si tu app aún hace polling para saber si una factura fue timbrada o si un pago fue exitoso, estás desperdiciando recursos y añadiendo latencia innecesaria. Los webhooks resuelven exactamente eso: gigstack te notifica en tiempo real cuando algo ocurre, y tu sistema reacciona. Este tutorial te lleva del registro del endpoint hasta el manejo robusto de eventos en producción 2026.

¿Por qué Event-Driven con gigstack API v2?

La arquitectura event-driven con webhooks tiene tres ventajas concretas frente al polling:

  • Latencia cero: tu endpoint recibe la notificación en cuanto el evento ocurre en gigstack.
  • Eficiencia: eliminas requests recurrentes al API, sin consumir cuota de rate limiting innecesariamente.
  • Desacoplamiento: tu lógica de negocio reacciona a hechos reales (pago confirmado, factura cancelada, recibo completado) en lugar de sondear estado.

La gigstack API v2 soporta 18 tipos de eventos en 5 categorías: Payments, Invoices, Receipts, Customers y Services. Un solo webhook puede suscribirse a múltiples eventos simultáneamente.

Paso 1: Autenticación y setup inicial

Obtén tu API token en app.gigstack.pro/settings?subtab=api. Todas las requests requieren Bearer token:

// config/gigstack.js - Node.js 20+ / 2026
const GIGSTACK_API_URL = 'https://api.gigstack.io/v2';
const GIGSTACK_TOKEN   = process.env.GIGSTACK_API_KEY;

export const gigstackHeaders = {
  'Authorization': `Bearer ${GIGSTACK_TOKEN}`,
  'Content-Type': 'application/json',
};

Paso 2: Registrar tu webhook endpoint

Usa POST /webhooks para crear tu endpoint. La URL debe ser HTTPS en producción. Suscríbete solo a los eventos que necesitas para reducir ruido y mejorar trazabilidad:

// scripts/create-webhook.js
import { gigstackHeaders, GIGSTACK_API_URL } from '../config/gigstack.js';

async function createWebhook() {
  const payload = {
    url: 'https://tuapp.com/webhooks/gigstack',
    events: [
      'payment.created',
      'payment.succeeded',
      'payment.canceled',
      'invoice.created',
      'invoice.failed',
      'receipt.completed',
    ],
    description: 'Produccion - eventos de pagos y facturacion 2026',
    status: 'active',
  };

  const res = await fetch(`${GIGSTACK_API_URL}/webhooks`, {
    method: 'POST',
    headers: gigstackHeaders,
    body: JSON.stringify(payload),
  });

  const data = await res.json();
  console.log('Webhook creado:', data.data.id); // wh_xxxxxxxx
  return data.data;
}

createWebhook();

La respuesta incluye el id del webhook (prefijo wh_), que usaras para actualizarlo o eliminarlo.

Paso 3: Construir el endpoint receptor

Tu servidor debe responder con 2xx en menos de 5 segundos. La regla de oro: acusa recibo rapido, procesa despues.

// server/webhooks.js - Express 4.x + Node.js 20
import express from 'express';
const router = express.Router();

// En memoria para dev; usa Redis en produccion
const processedEvents = new Set();

router.post('/gigstack', express.json(), async (req, res) => {
  const event = req.body;

  // 1. Acusa recibo INMEDIATAMENTE
  res.status(200).json({ received: true });

  // 2. Idempotencia: evita procesar el mismo evento dos veces
  if (processedEvents.has(event.id)) {
    console.log(`Evento duplicado ignorado: ${event.id}`);
    return;
  }
  processedEvents.add(event.id);

  // 3. Despacha segun tipo de evento
  try {
    await handleGigstackEvent(event);
  } catch (err) {
    console.error(`Error procesando ${event.id}:`, err);
    // No relanzar - ya respondiste 200, loguea para revision manual
  }
});

export default router;

Paso 4: Manejar eventos por tipo

gigstack envia el payload completo del objeto que disparo el evento dentro de data.object. El campo livemode: true indica produccion; false es sandbox (test API key).

// server/handlers/gigstack-events.js

async function handleGigstackEvent(event) {
  const { type, data, livemode } = event;
  const obj = data.object;

  console.log(`[gigstack] Evento: ${type} | livemode: ${livemode}`);

  switch (type) {

    case 'payment.succeeded':
      // Pago confirmado - activa entrega, envia email, actualiza DB
      await db.payments.update(
        { externalId: obj.id },
        { status: 'paid', paidAt: new Date(obj.created_at) }
      );
      await emailService.sendPaymentConfirmation({
        to: obj.customer?.email,
        amount: obj.amount,
      });
      break;

    case 'invoice.created':
      // Factura timbrada ante el SAT - guarda UUID y PDF
      await db.invoices.upsert({
        gigstackId: obj.id,
        uuid:    obj.uuid,   // UUID CFDI 4.0
        xmlUrl:  obj.xml_url,
        pdfUrl:  obj.pdf_url,
        status:  'stamped',
      });
      break;

    case 'invoice.failed':
      // Error al timbrar - notifica al equipo para revision
      console.error('Timbrado fallido:', obj.cfdi_error_code);
      await alertService.notify(
        `Factura ${obj.id} fallo: ${obj.cfdi_error_description}`
      );
      break;

    case 'receipt.completed':
      // Cliente completo su autofactura - sincroniza con ERP
      await erpSync.pushInvoice({ receiptId: obj.id, uuid: obj.uuid });
      break;

    case 'payment.canceled':
      await db.payments.update(
        { externalId: obj.id },
        { status: 'canceled' }
      );
      break;

    default:
      console.log(`Evento no manejado: ${type}`);
  }
}

export { handleGigstackEvent };

Paso 5: Idempotencia robusta con Redis

Para produccion, reemplaza el Set en memoria por Redis. TTL de 48 horas cubre cualquier ventana de reintentos de gigstack:

// utils/idempotency.js - con ioredis
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);

export async function isAlreadyProcessed(eventId) {
  const key = `gigstack:event:${eventId}`;
  // NX = solo setea si no existe; null = ya existia
  const result = await redis.set(key, '1', 'EX', 172800, 'NX');
  return result === null;
}

// Uso en el endpoint:
// if (await isAlreadyProcessed(event.id)) return;

Paso 6: Testing local con ngrok

Para probar el flujo completo sin deploy, levanta un tunel ngrok hacia tu servidor local:

# 1. Levanta tu servidor Express
node server/index.js

# 2. En otra terminal, crea el tunel
ngrok http 3000
# Resultado: https://abc123.ngrok-free.app

# 3. Registra el webhook con la URL del tunel
curl -X POST https://api.gigstack.io/v2/webhooks \
  -H "Authorization: Bearer $GIGSTACK_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://abc123.ngrok-free.app/webhooks/gigstack",
    "events": ["payment.succeeded", "invoice.created"],
    "status": "active"
  }'

Usa tu test API key para que los eventos tengan livemode: false y no afecten datos reales. El staging comparte la misma URL base: https://api.gigstack.io/v2.

Paso 7: Administrar webhooks existentes

// Listar webhooks activos
const res = await fetch(
  `${GIGSTACK_API_URL}/webhooks?status=active&limit=50`,
  { headers: gigstackHeaders }
);
const { data: webhooks } = await res.json();
console.table(
  webhooks.map(w => ({ id: w.id, url: w.url, eventos: w.events.length }))
);

// Desactivar temporalmente sin eliminar
await fetch(`${GIGSTACK_API_URL}/webhooks/wh_xxxxxxxx`, {
  method: 'PUT',
  headers: gigstackHeaders,
  body: JSON.stringify({ status: 'inactive' }),
});

// Eliminar definitivamente
await fetch(`${GIGSTACK_API_URL}/webhooks/wh_xxxxxxxx`, {
  method: 'DELETE',
  headers: gigstackHeaders,
});

Estructura del payload de un evento

Cuando ocurre un evento, gigstack envia un HTTP POST a tu endpoint con esta estructura:

{
  "id": "evt_1234567890",
  "type": "payment.succeeded",
  "created": 1709090576567,
  "livemode": true,
  "data": {
    "object": {
      "id": "payment_1234567890",
      "amount": 1000.00,
      "status": "succeeded"
    }
  }
}

El campo id (prefijo evt_) es tu clave de idempotencia. livemode distingue produccion de sandbox. data.object contiene el recurso completo que disparo el evento.

Eventos disponibles en gigstack API v2

Payments: payment.created, payment.updated, payment.succeeded, payment.canceled, payment.deleted, payment.upcoming_due_date
Invoices: invoice.created, invoice.canceled, invoice.failed
Receipts: receipt.created, receipt.updated, receipt.completed, receipt.deleted
Customers: customer.created, customer.updated, customer.deleted
Services: service.created, service.updated, service.deleted

Automatiza cada venta con gigstack

Con los webhooks configurados, tu sistema reacciona automaticamente a cada pago, factura y recibo sin intervencion manual, con cumplimiento SAT incluido. gigstack se encarga del timbrado CFDI 4.0; tu te enfocas en tu logica de negocio. Comienza en gigstack.pro y conecta tu primer webhook en minutos.


FAQ Tecnica: Troubleshooting de Webhooks gigstack 2026

Mi servidor no respondio a tiempo y gigstack puede reintentar el evento. Como evito duplicados?

Usa event.id (prefijo evt_) como clave unica en Redis con TTL de 48h. Antes de procesar cualquier evento, verifica si ese ID ya existe en Redis: si existe, ignora el evento. Esta es la implementacion de idempotencia del Paso 5. Sin esto, un reintento puede disparar emails duplicados o actualizar saldos dos veces.

Por que mi webhook recibe eventos con livemode: false incluso en produccion?

Estas usando tu test API key en lugar de la production key. El webhook hereda el modo del API key con el que fue creado. Verifica en app.gigstack.pro/settings?subtab=api que el token corresponde al entorno correcto. Los webhooks creados con test key solo reciben eventos de sandbox.

El body de data.object llega vacio. Por que?

Falta el middleware JSON en Express. Agrega express.json() antes del handler o como middleware global. Sin el, el body llega como buffer y el parse falla silenciosamente. Tambien verifica que el Content-Type del request entrante sea application/json.

Puedo recibir eventos de multiples equipos con gigstack Connect?

Si. Agrega el parametro team al crear el webhook con el ID del equipo destino. Tu API key debe pertenecer a un equipo con gigstack Connect habilitado y el equipo destino debe compartir la misma cuenta de facturacion. Referencia completa en la documentacion oficial.


Recursos: Webhooks gigstack API Docs · gigstack API Reference · webhook.site · ngrok Docs · gigstack Connect Guide

Blogs que te pueden gustar