Buenas prácticas con webhooks
Responde rápido, procesa después
Sección titulada «Responde rápido, procesa después»Verifica la firma, encola el evento (fila en base de datos, cola, tarea en segundo plano) y devuelve 2xx de inmediato. SpacePost espera como máximo 15 segundos, y un manejador lento se convierte en reintentos y duplicados.
Sé idempotente
Sección titulada «Sé idempotente»La entrega es de al menos una vez. Guarda el webhook-id de cada entrega procesada (basta una restricción de unicidad) y omite las repeticiones.
const inserted = await db.insert(processedWebhooks).values({ id: webhookId }).onConflictDoNothing().returning();if (inserted.length === 0) return new Response("duplicate", { status: 200 });Verifica siempre las firmas
Sección titulada «Verifica siempre las firmas»Usa el cuerpo sin procesar, rechaza las marcas de tiempo con más de 5 minutos de antigüedad y compara las firmas en tiempo constante (el SDK y las bibliotecas lo hacen). Consulta Verificar firmas.
No confíes en el orden
Sección titulada «No confíes en el orden»Los eventos pueden llegar desordenados, sobre todo tras reintentos. Compara el created_at del payload con lo que tienes guardado y aplica solo los cambios que hagan avanzar el estado. El propio last_event de SpacePost sigue la misma regla.
Actúa según los eventos que importan
Sección titulada «Actúa según los eventos que importan»| Evento | Acción habitual |
|---|---|
email.bounced |
Marca la dirección como no válida en tu base de datos; deja de enviarle. |
email.complained |
Da de baja de inmediato al usuario del correo no esencial. |
email.delivery_delayed |
Normalmente nada; avisa si es un correo urgente (restablecimiento de contraseña). |
email.failed |
Registra data.failed.reason, avisa y, si procede, reintenta con una corrección. |
email.suppressed |
Un destinatario estaba en tu lista de supresión; muéstralo en tu interfaz de administración. |
Suscríbete solo a los eventos que gestionas. Menos eventos significan menos tráfico y menos fallos.
Protege el endpoint
Sección titulada «Protege el endpoint»- Sírvelo por HTTPS con un certificado válido.
- No registres secretos ni payloads completos que contengan datos personales.
- Usa una ruta dedicada sin ningún otro comportamiento y devuelve un cuerpo genérico.
- Guarda el
signing_secreten un gestor de secretos, no en el control de versiones.
Monitoriza
Sección titulada «Monitoriza»Vigila el registro de entregas del panel o configura alertas ante fallos repetidos: si tu endpoint está caído más de unas 27 horas, se agotan todos los reintentos y tendrás que reenviar manualmente.