Webhooks: suscríbase a eventos de enlaces y del workspace

Envíe solicitudes HTTP POST firmadas desde Elido a su servidor cuando cambien los enlaces, dominios, miembros y su workspace. Encabezados, payloads, reintentos, registro de entregas y rotación de secretos.

10 min de lecturaActualizado 2026-09-22

Lo que configurará

  • Un endpoint que recibe eventos de Elido como link.created, link.updated, link.deleted, member.invited y domain.verified.
  • Verificación HMAC-SHA256 del encabezado X-Elido-Signature, para que su servidor pueda confirmar que cada entrega procede de Elido.
  • Tres intentos de entrega por evento, un registro de entregas con un botón manual **Retry** y rotación de secretos con una superposición de 7 días.

Los webhooks envían eventos de Elido a su servidor en cuanto ocurren, por lo que no tiene que consultar la API periódicamente. Usos habituales: sincronizar metadatos de enlaces con un CRM, mantener actualizado un índice interno de enlaces o iniciar un trabajo cuando se publica un enlace.

Los webhooks cubren cambios en enlaces, dominios, miembros y el workspace. No contienen clics individuales. Para obtener datos de clics, use la exportación de clics o una integración de eventos como Mixpanel. Los eventos de webhook por clic están planificados.

Añadir un endpoint de webhook

  1. Vaya a Dashboard → Webhooks.
  2. Introduzca la URL a la que debemos enviar el POST y una descripción opcional.
  3. Elija el tipo de endpoint: Events (usted elige los tipos de evento) o SIEM (firehose) (todos los eventos del workspace).
  4. En un endpoint de Events, marque los tipos de evento que quiera. Los eventos link.* vienen marcados de forma predeterminada.
  5. Haga clic en Add endpoint. El secreto de firma aparece una sola vez, justo debajo del formulario. Cópielo ahora: Elido no volverá a mostrarlo.

La URL debe ser HTTPS. Las URL http:// simples se rechazan al guardar el endpoint, excepto localhost y 127.0.0.1, que siguen permitidas para el desarrollo local.

Puede pausar y reanudar un endpoint desde la lista. Un endpoint pausado no recibe nuevas entregas, y todo lo que siga en cola para él espera hasta que lo reanude.

Quién puede gestionar los webhooks

Cualquier persona del workspace puede ver los endpoints y el registro de entregas. Crear, editar, pausar, eliminar, rotar el secreto y reintentar una entrega requiere el permiso workspace.edit, que tienen los roles integrados Admin y Owner. Una clave de API puede llamar a los mismos endpoints de webhook de la API si su rol tiene ese permiso.

Tipos de endpoint

  • Events (event): recibe solo los tipos de evento a los que se suscribió. Firmado.
  • SIEM (siem): recibe todos los eventos publicados para el workspace, incluido audit.event por cada entrada del registro de auditoría. Firmado. Está pensado para pipelines de registros y herramientas de seguridad.
  • Discord, Telegram y Sentry: canales de chat y alertas que reutilizan el mismo sistema de entregas, pero envían el formato de mensaje propio del proveedor. Se autentican mediante la URL o el token del proveedor, por lo que no llevan encabezados de firma. Consulte Discord, Telegram y Sentry.

Todo lo que se explica a continuación sobre firmas y secretos se aplica únicamente a los endpoints Events y SIEM.

Catálogo de eventos

Los nombres siguen el formato <resource>.<action>. El formulario del dashboard ofrece los más habituales; mediante la API puede suscribir un endpoint Events a cualquier tipo de esta lista, y un endpoint SIEM recibe todos.

En el selector del dashboard:

  • link.created: se creó un enlace corto, incluidos los enlaces creados en bloque.
  • link.updated: cambió un enlace (destino, título, etiquetas, caducidad, etc.), se restauró, cambió su estado o la moderación cambió su estado de seguridad.
  • link.deleted: un enlace se eliminó de forma lógica.
  • workspace.updated: cambiaron los ajustes del workspace.
  • workspace.created: se publica cuando se crea un workspace. Como no puede existir ningún endpoint en un workspace antes de que se cree, normalmente no recibirá este evento.
  • member.invited: alguien se unió al workspace mediante una adición directa, al aceptar una invitación o mediante el aprovisionamiento de SCIM.
  • member.removed: se eliminó un miembro manualmente o mediante SCIM.
  • audit.event: un evento por cada entrada del registro de auditoría.

Disponibles mediante la API o un endpoint SIEM:

  • link.expired: un enlace pasó su fecha de caducidad.
  • link.cap_reached: un enlace alcanzó su límite de clics. data incluye cap y clicks.
  • link.broken: la comprobación del estado del enlace de Elido detectó que el destino falla. data incluye status_code, error_message y first_seen_at.
  • link.encrypted_created y link.encryption_rotated: para enlaces cifrados.
  • domain.verified: un dominio personalizado superó su comprobación de DNS.
  • domain.ssl_failed: los registros DNS de un dominio personalizado seguían sin encontrarse 24 horas después de añadirlo. A pesar del nombre, se refiere a la verificación de DNS, no a la renovación del certificado.
  • member.role_changed: cambió el rol de un miembro. data incluye old_role, new_role y changed_by_user_id.
  • invitation.created y invitation.accepted.
  • Eventos de facturación: subscription.* (por ejemplo, subscription.activated, subscription.renewed, subscription.canceled) y usage.threshold_80, usage.threshold_100.

Planificados, no se envían actualmente: link.clicked.aggregated (recuentos de clics por enlace y ventana), eventos por clic, conversion.recorded, domain.tls_renewed, qr.generated y un evento independiente abuse.flagged. Actualmente, una decisión de moderación sobre un enlace llega como link.updated con el nuevo abuse_status.

Estructura del payload

Cada entrega firmada es un POST con Content-Type: application/json, User-Agent: Elido-Webhooks/1.0 y este sobre:

{
  "type": "link.created",
  "workspace_id": 4123,
  "timestamp": "2026-09-22T09:42:11Z",
  "data": {
    "id": 891234,
    "workspace_id": 4123,
    "domain_id": 12,
    "slug": "spring-2026",
    "destination_url": "https://acme.com/spring-sale",
    "title": "Spring sale",
    "tags": ["email"],
    "status": "active",
    "expires_at": null,
    "created_by_user_id": 5821,
    "created_at": "2026-09-22T09:42:11Z"
  }
}
  • type es el tipo de evento. También aparece en el encabezado X-Webhook-Event.
  • timestamp indica cuándo ocurrió el evento, en UTC.
  • data depende del evento. Para los eventos link.* es el objeto de enlace completo (el ejemplo anterior está recortado). Para otros eventos es un objeto pequeño con los ID y campos indicados en el catálogo.
  • Los secretos nunca salen de Elido: los campos como el hash de la contraseña de un enlace o un token de invitación se eliminan de data antes de la entrega.

Todavía no hay un campo id de evento en el cuerpo; está previsto añadir un ID por evento. Para la idempotencia, use el encabezado X-Webhook-Delivery, que se describe a continuación.

Encabezados y firmas

Cada entrega a un endpoint Events o SIEM lleva:

EncabezadoValor
X-Elido-Signaturev1= seguido de la firma HMAC-SHA256 hexadecimal
X-Webhook-SignatureEl mismo valor que X-Elido-Signature, conservado para integraciones antiguas
X-Webhook-TimestampHora Unix en segundos en la que se firmó esta solicitud
X-Webhook-EventEl tipo de evento, por ejemplo link.created
X-Webhook-DeliveryEl ID de entrega. Se mantiene igual en los reintentos de la misma entrega
X-Elido-Signature-PreviousSolo durante una rotación de secretos: la misma firma creada con la clave anterior

La firma se calcula así:

v1=hex( HMAC-SHA256( secret, "{X-Webhook-Timestamp}.{raw request body}" ) )

La clave es toda la cadena de su secreto, incluido el prefijo whsec_, usada tal cual. Firme los bytes sin procesar que recibió, no un objeto JSON serializado de nuevo, y compare en tiempo constante. Un ejemplo corto en Node (Express):

import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";

const SECRET = process.env.ELIDO_WEBHOOK_SECRET; // full whsec_... value

function same(a, b = "") {
  const x = Buffer.from(a);
  const y = Buffer.from(b);
  return x.length === y.length && timingSafeEqual(x, y);
}

const app = express();
app.post(
  "/webhooks/elido",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ts = req.get("X-Webhook-Timestamp") ?? "";
    if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
      return res.status(400).send("stale timestamp");
    }
    const expected =
      "v1=" +
      createHmac("sha256", SECRET)
        .update(`${ts}.`)
        .update(req.body)
        .digest("hex");
    const ok = [
      req.get("X-Elido-Signature"),
      req.get("X-Elido-Signature-Previous"),
    ].some((sig) => same(expected, sig));
    if (!ok) return res.status(401).send("bad signature");

    const event = JSON.parse(req.body.toString("utf8"));
    // queue event for processing, then answer quickly
    res.sendStatus(200);
  },
);

Para ver versiones en Python y Go, un vector de prueba y los errores habituales, consulte cómo verificar las firmas de webhook.

Rotar el secreto de firma

Abra el endpoint en Dashboard → Webhooks y haga clic en Rotate secret. El nuevo secreto whsec_ se muestra una sola vez y, a partir de entonces, Elido firma con él.

La clave anterior sigue siendo válida durante una ventana de gracia de 7 días. Durante esa ventana, cada entrega lleva dos firmas: X-Elido-Signature con la clave nueva y X-Elido-Signature-Previous con la anterior, de modo que un receptor que todavía no haya cambiado sigue pudiendo verificar. Acepte cualquiera de los dos encabezados mientras implementa el nuevo secreto.

Los endpoints creados antes del 22 de septiembre de 2026 son una excepción: su primera rotación no genera X-Elido-Signature-Previous, por lo que el secreto original deja de funcionar de inmediato. Implemente el nuevo secreto justo después de esa primera rotación. Los endpoints creados desde entonces firman con ambas claves desde la primera rotación. A partir de la segunda rotación se aplica la superposición de 7 días.

Reintentos

Una entrega falla con cualquier respuesta que no sea 2xx, un error de red o si no hay respuesta en 10 segundos. Cada entrega recibe 3 intentos en total:

  1. El primer intento, unos segundos después del evento.
  2. Un reintento unos 5 minutos después del primer fallo.
  3. Un último reintento unos 15 minutos después del segundo fallo.

Si falla el tercer intento, la entrega se marca como failed y no vuelve a reintentarse automáticamente. El endpoint sigue activo y se siguen entregando los eventos nuevos. Su endpoint puede ver la misma entrega más de una vez (por ejemplo, si procesó una solicitud, pero respondió después del tiempo de espera de 10 segundos), así que elimine duplicados usando X-Webhook-Delivery.

Registro de entregas

Abra un endpoint en Dashboard → Webhooks para ver sus 100 entregas más recientes. Para cada una obtiene el tipo de evento, el estado (pending, delivered o failed), el estado HTTP que devolvió su servidor, el tiempo de respuesta, los intentos usados de un total de 3, cuándo se creó y terminó, la hora del próximo reintento para las pendientes, el último error y el payload completo que se envió.

Cualquier entrega entregada o fallida tiene un botón Retry. Vuelve a poner en cola la misma entrega (el mismo ID X-Webhook-Delivery, con una firma nueva) con un presupuesto nuevo de 3 intentos. Mediante la API, GET /v1/workspaces/{workspace_id}/webhooks/{id}/deliveries pagina las entregas anteriores con limit (hasta 100) y offset, y POST .../deliveries/{delivery_id}/retry hace lo mismo que el botón. Si no puede repetir una entrega por su cuenta, el soporte de Elido puede repetirla por usted.

Está previsto registrar en el log el cuerpo de respuesta de su servidor.

Pruebas locales

Está previsto un comando de CLI que reenvíe webhooks a localhost (npx @elido/cli webhooks forward). Hasta entonces, exponga su servidor local mediante un túnel como ngrok o Cloudflare Tunnel, añada la URL HTTPS del túnel como endpoint y elimínelo cuando termine.

Límites

  • 10 segundos para que responda su endpoint.
  • 3 intentos de entrega por evento, más los reintentos manuales.
  • La API del registro de entregas devuelve como máximo 100 entregas por página.

Solución de problemas

La firma nunca coincide. Las causas habituales son que su framework analizó y volvió a serializar el JSON antes de que lo calculara (calcule el hash del cuerpo sin procesar), que eliminó el prefijo whsec_ de la clave o que firmó con el timestamp del cuerpo en lugar del encabezado X-Webhook-Timestamp. La publicación sobre verificación de firmas incluye un vector de prueba para comprobar su código.

La firma dejó de coincidir después de una rotación. Su servidor todavía tiene el secreto anterior. Implemente el nuevo. En un endpoint creado antes del 22 de septiembre de 2026, la primera rotación no tiene ningún X-Elido-Signature-Previous al que recurrir.

Algunos eventos llegan dos veces. Elido reintentó porque su endpoint respondió con un error o tardó más de 10 segundos. Elimine duplicados usando X-Webhook-Delivery y responda con un 2xx antes de realizar trabajos lentos.

Nunca llega un tipo de evento. Compruebe que el endpoint está suscrito a él y no está pausado, y que el tipo figura en el catálogo anterior. Los tipos marcados como planificados todavía no se envían.

¿Te ha sido útil?
¿Necesitas más? Escribe al equipo - respuesta en un día laborable.Contactar con soporte