Skip to Content
WebhooksEjemplos

Ejemplos de webhooks

Esta página ofrece ejemplos completos y listos para producción para recibir y procesar webhooks de Ignite en distintos lenguajes.

Ejemplos de servidor completos

// pages/api/webhook.ts import { createHmac, timingSafeEqual } from "crypto"; import { NextApiRequest, NextApiResponse } from "next"; // Disable body parser to access raw body for signature verification export const config = { api: { bodyParser: false, }, }; interface ThumbnailFormat { url: string; fileSize: number; } interface ThumbnailVariant { name: string; width: number; height: number; formats: { jpeg: ThumbnailFormat; webp: ThumbnailFormat; }; } interface VideoWebhookData { id: string; status: "COMPLETE" | "PROCESSING" | "NO_FILE" | "FAILED"; title: string; src?: { thumbnails?: ThumbnailVariant[]; thumbnailUrl?: string; // deprecated — use src.thumbnails instead mp4?: Array<{ name: string; url: string; width: number; height: number }>; }; // ... other video properties } async function getRawBody(req: NextApiRequest): Promise<string> { const chunks: Buffer[] = []; for await (const chunk of req) { chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk); } return Buffer.concat(chunks).toString("utf-8"); } function isValidSignature( rawBody: string, signatureHeader: string | string[] | undefined, secret: string ): boolean { try { if (typeof signatureHeader !== "string") { return false; } const time = signatureHeader.match(/t=(\d+)/)?.[1]; const token = signatureHeader.match(/v1=(\w+)/)?.[1]; if (!time || !token) { return false; } const signedPayload = `${time}.${rawBody}`; const hmac = createHmac("sha256", secret); const calculatedSignature = hmac.update(signedPayload).digest("hex"); return timingSafeEqual( Buffer.from(token), Buffer.from(calculatedSignature) ); } catch { return false; } } export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== "POST") { return res.status(405).end(); } const rawBody = await getRawBody(req); if ( !isValidSignature( rawBody, req.headers["x-webhook-signature"], process.env.WEBHOOK_SIGNING_SECRET! ) ) { console.error("Invalid webhook signature"); return res.status(403).end(); } const eventType = req.headers["x-webhook-event"]; const deliveryId = req.headers["x-webhook-delivery-id"]; const video = JSON.parse(rawBody) as VideoWebhookData; // Process based on event type switch (eventType) { case "video.created": console.log("New video created:", video.id, video.title); // await handleVideoCreated(video); break; case "video.updated": console.log("Video updated:", video.id, video.title); if (video.status === "COMPLETE") { // Video processing finished - update your database // await db.updateVideo(video.id, { // thumbnails: video.src?.thumbnails, // thumbnail: video.src?.thumbnails?.[0]?.formats.jpeg.url, // sizes: video.src?.mp4, // }); } break; case "video.deleted": console.log("Video deleted:", video.id); // await handleVideoDeleted(video); break; } return res.status(204).end(); }

Entregas de webhook

Cada intento de entrega de un webhook queda registrado. Si una entrega falla, el sistema reintentará automáticamente.

Estado de la entrega

EstadoDescripción
successEl evento se entregó correctamente (respuesta HTTP 2xx)
failedLa entrega falló (tiempo de espera agotado, HTTP 4xx/5xx, error de red)

Información de la entrega

Cada registro de entrega incluye:

CampoDescripción
responseCodeCódigo de estado HTTP devuelto por tu endpoint
responseBodyCuerpo de la respuesta de tu endpoint (truncado si es muy largo)
errorMessageMensaje de error si la entrega falló
deliveredAtMarca de tiempo del intento de entrega
attemptNumberNúmero de intento (aumenta con los reintentos)
nextRetryAtCuándo se intentará el siguiente reintegro (si aplica)

Comportamiento de reintentos

  • Las entregas fallidas se reintentan automáticamente
  • Si nextRetryAt tiene valor, hay un reintegro programado
  • Si nextRetryAt no tiene valor, no habrá más reintentos

Buenas prácticas

Seguir estas buenas prácticas mejora la fiabilidad del procesamiento de webhooks y facilita depurar incidencias.

Tiempo de respuesta

Tu endpoint debe responder en 30 segundos como máximo. Para operaciones largas, confirma el webhook al instante y procesa de forma asíncrona:

app.post('/webhook', async (req, res) => { // Immediately acknowledge receipt res.status(200).json({ received: true }); // Process asynchronously (don't await) processWebhookAsync(req.body).catch(console.error); }); async function processWebhookAsync(video) { // Long-running operations here }

Seguridad

  • Protege los secretos — No expongas el secreto de firma en código del cliente ni en el control de versiones
  • Usa HTTPS — En producción, usa siempre endpoints HTTPS
  • Valida todo — Verifica siempre las firmas antes de procesar
  • Limitación de tasa — Valora aplicar rate limiting en tu endpoint

Fiabilidad

  • Idempotencia — Guarda y comprueba X-Webhook-Delivery-Id para gestionar entregas duplicadas
  • Registro — Registra todas las solicitudes de webhook para depurar
  • Monitorización — Configura alertas ante fallos en el procesamiento
  • Manejo de errores — Devuelve códigos HTTP adecuados para que los reintentos funcionen bien

Códigos de estado HTTP

CódigoSignificado
200-299Éxito — evento procesado
4xxError de cliente — se reintentará
5xxError de servidor — se reintentará

Resolución de problemas

No recibes eventos

  1. Comprueba que la suscripción al webhook esté activa
  2. Verifica que los tipos de evento correctos estén seleccionados
  3. Asegúrate de que los eventos ocurren en el espacio de trabajo correcto
  4. Revisa los logs del servidor por solicitudes entrantes

Falla la verificación de firma

  1. Confirma que usas el secreto de firma correcto (no un token de API)
  2. Asegúrate de que el cuerpo de la solicitud no se modifica antes de verificar
  3. Comprueba que la serialización JSON coincide (compacta, sin espacios extra)
  4. Verifica que el formato de la cabecera de firma se parsea bien: t=timestamp,v1=signature

Errores de tiempo de espera

  1. Responde en 30 segundos como máximo
  2. Mueve las operaciones largas a procesamiento en segundo plano
  3. Devuelve 200 de inmediato y procesa de forma asíncrona

Eventos duplicados

  1. Implementa idempotencia con X-Webhook-Delivery-Id
  2. Revisa attemptNumber en los reintentos
  3. Guarda los IDs de entrega procesados en una base de datos