Webhook: sottoscrivi gli eventi dei link e del workspace

Invia POST HTTP firmati da Elido al tuo server quando cambiano link, domini, membri e il tuo workspace. Header, payload, retry, log di consegna e rotazione dei secret.

10 min di letturaAggiornato 2026-09-22

Cosa configurerai

  • Un endpoint che riceve eventi Elido come link.created, link.updated, link.deleted, member.invited e domain.verified.
  • La verifica HMAC-SHA256 dell'header X-Elido-Signature, così il tuo server può confermare che ogni consegna proviene da Elido.
  • Tre tentativi di consegna per evento, un log di consegna con un pulsante manuale Retry e la rotazione dei secret con una sovrapposizione di 7 giorni.

I webhook inviano gli eventi da Elido al tuo server man mano che si verificano, così non devi interrogare l'API a intervalli regolari. Usi tipici: sincronizzare i metadati dei link con un CRM, mantenere aggiornato un indice interno dei link o avviare un job quando viene pubblicato un link.

I webhook coprono le modifiche a link, domini, membri e workspace. Non trasportano i clic singoli. Per i dati sui clic, usa l'esportazione dei clic o un'integrazione per eventi come Mixpanel. Gli eventi webhook per singolo clic sono pianificati.

Aggiungi un endpoint webhook

  1. Vai in Dashboard → Webhooks.
  2. Inserisci l'URL a cui dobbiamo inviare il POST e una descrizione facoltativa.
  3. Scegli il tipo di endpoint: Events (scegli tu i tipi di evento) o SIEM (firehose) (ogni evento del workspace).
  4. Per un endpoint Events, seleziona i tipi di evento che vuoi. Gli eventi link.* sono selezionati per impostazione predefinita.
  5. Fai clic su Add endpoint. Il signing secret viene mostrato una sola volta, subito sotto il modulo. Copialo ora: Elido non lo mostrerà più.

L'URL deve usare HTTPS. http:// semplice viene rifiutato quando salvi l'endpoint, ad eccezione di localhost e 127.0.0.1, che restano consentiti per lo sviluppo locale.

Puoi mettere in pausa e riattivare un endpoint dall'elenco. Un endpoint in pausa non riceve nuove consegne e tutto ciò che è ancora in coda per lui resta in attesa finché non lo riattivi.

Chi può gestire i webhook

Chiunque faccia parte del workspace può visualizzare gli endpoint e il log di consegna. Per creare, modificare, mettere in pausa, eliminare, ruotare il secret e ritentare una consegna serve il permesso workspace.edit, disponibile nei ruoli integrati Admin e Owner. Una chiave API può chiamare gli stessi endpoint webhook dell'API se il suo ruolo dispone di quel permesso.

Tipi di endpoint

  • Events (event): riceve solo i tipi di evento a cui ti sei iscritto. Firmato.
  • SIEM (siem): riceve ogni evento pubblicato per il workspace, incluso audit.event per ogni voce del log di audit. Firmato. Pensato per pipeline di log e strumenti di sicurezza.
  • Discord, Telegram e Sentry: canali di chat e avvisi che riutilizzano lo stesso sistema di consegna, ma inviano il formato di messaggio del fornitore. Si autenticano tramite l'URL o il token del fornitore, quindi non includono header di firma. Vedi Discord, Telegram e Sentry.

Tutto ciò che segue su firme e secret si applica solo agli endpoint Events e SIEM.

Catalogo degli eventi

I nomi seguono il formato <resource>.<action>. Il modulo della dashboard offre quelli più comuni; tramite l'API puoi sottoscrivere un endpoint Events a qualsiasi tipo presente in questo elenco, mentre un endpoint SIEM li riceve tutti.

Nel selettore della dashboard:

  • link.created: è stato creato un short link, inclusi quelli creati in blocco.
  • link.updated: un link è cambiato (destinazione, titolo, tag, scadenza e così via), è stato ripristinato, ha cambiato stato oppure il suo stato di sicurezza è stato modificato dalla moderazione.
  • link.deleted: un link è stato eliminato logicamente.
  • workspace.updated: sono cambiate le impostazioni del workspace.
  • workspace.created: viene pubblicato quando viene creato un workspace. Poiché prima della sua creazione non può esistere alcun endpoint nel workspace, normalmente non riceverai questo evento.
  • member.invited: qualcuno è entrato nel workspace tramite aggiunta diretta, accettazione di un invito o provisioning SCIM.
  • member.removed: un membro è stato rimosso manualmente o tramite SCIM.
  • audit.event: un evento per ogni voce del log di audit.

Disponibili tramite l'API o un endpoint SIEM:

  • link.expired: un link ha superato la propria data di scadenza.
  • link.cap_reached: un link ha raggiunto il proprio limite di clic. data include cap e clicks.
  • link.broken: il controllo dello stato del link di Elido ha rilevato che la destinazione non funziona. data include status_code, error_message e first_seen_at.
  • link.encrypted_created e link.encryption_rotated: per i link crittografati.
  • domain.verified: un dominio personalizzato ha superato il controllo DNS.
  • domain.ssl_failed: i record DNS di un dominio personalizzato non erano ancora stati trovati 24 ore dopo la sua aggiunta. Nonostante il nome, riguarda la verifica DNS, non il rinnovo del certificato.
  • member.role_changed: è cambiato il ruolo di un membro. data include old_role, new_role e changed_by_user_id.
  • invitation.created e invitation.accepted.
  • Eventi di fatturazione: subscription.* (ad esempio subscription.activated, subscription.renewed, subscription.canceled) e usage.threshold_80, usage.threshold_100.

Pianificati e non ancora inviati: link.clicked.aggregated (conteggi dei clic per link e per finestra), eventi per singolo clic, conversion.recorded, domain.tls_renewed, qr.generated e un evento separato abuse.flagged. Una decisione di moderazione su un link arriva attualmente come link.updated con il nuovo abuse_status.

Struttura del payload

Ogni consegna firmata è un POST con Content-Type: application/json, User-Agent: Elido-Webhooks/1.0 e questo envelope:

{
  "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 è il tipo di evento. È presente anche nell'header X-Webhook-Event.
  • timestamp indica quando si è verificato l'evento, in UTC.
  • data dipende dall'evento. Per gli eventi link.* è l'oggetto link completo (l'esempio sopra è abbreviato). Per gli altri eventi è un piccolo oggetto con gli ID e i campi elencati nel catalogo.
  • I secret non lasciano mai Elido: campi come l'hash della password di un link o un token di invito vengono rimossi da data prima della consegna.

Nel body non c'è ancora un campo id dell'evento; è pianificato un ID per evento. Per l'idempotenza usa l'header X-Webhook-Delivery, descritto di seguito.

Header e firme

Ogni consegna a un endpoint Events o SIEM include:

HeaderValore
X-Elido-Signaturev1= seguito dalla firma HMAC-SHA256 esadecimale
X-Webhook-SignatureLo stesso valore di X-Elido-Signature, mantenuto per le integrazioni precedenti
X-Webhook-TimestampOra Unix in secondi in cui questa richiesta è stata firmata
X-Webhook-EventIl tipo di evento, ad esempio link.created
X-Webhook-DeliveryL'ID della consegna. Rimane uguale tra i retry della stessa consegna
X-Elido-Signature-PreviousSolo durante una rotazione del secret: la stessa firma generata con la chiave precedente

La firma viene calcolata così:

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

La chiave è l'intera stringa del tuo secret, incluso il prefisso whsec_, usata così com'è. Firma i byte raw ricevuti, non un oggetto JSON serializzato di nuovo, e confronta in tempo costante. Un breve esempio 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);
  },
);

Per le versioni Python e Go, un test vector e gli errori più comuni, vedi come verificare le firme dei webhook.

Ruotare il signing secret

Apri l'endpoint in Dashboard → Webhooks e fai clic su Rotate secret. Il nuovo secret whsec_ viene mostrato una sola volta e da quel momento Elido firma con quello.

La chiave precedente resta valida per un periodo di tolleranza di 7 giorni. Durante questo periodo ogni consegna include due firme: X-Elido-Signature con la nuova chiave e X-Elido-Signature-Previous con quella precedente, così un destinatario che non ha ancora effettuato il passaggio continua a verificare. Accetta entrambi gli header mentre distribuisci il nuovo secret.

Gli endpoint creati prima del 22 settembre 2026 sono un'eccezione: la loro prima rotazione non produce X-Elido-Signature-Previous, quindi il secret originale smette di funzionare immediatamente. Distribuisci il nuovo secret subito dopo la prima rotazione. Gli endpoint creati da allora includono entrambe le firme già dalla prima rotazione. Dalla seconda rotazione in poi si applica la sovrapposizione di 7 giorni.

Retry

Una consegna fallisce con qualsiasi risposta non-2xx, un errore di rete o l'assenza di risposta entro 10 secondi. Ogni consegna ha 3 tentativi in totale:

  1. Il primo tentativo, pochi secondi dopo l'evento.
  2. Un retry circa 5 minuti dopo il primo errore.
  3. Un ultimo retry circa 15 minuti dopo il secondo errore.

Se il terzo tentativo fallisce, la consegna viene contrassegnata come failed e non viene ritentata di nuovo automaticamente. L'endpoint resta attivo e i nuovi eventi continuano a essere consegnati. Il tuo endpoint può vedere la stessa consegna più di una volta (ad esempio quando ha elaborato una richiesta, ma ha risposto dopo il timeout di 10 secondi), quindi elimina i duplicati usando X-Webhook-Delivery.

Log di consegna

Apri un endpoint in Dashboard → Webhooks per vedere le sue 100 consegne più recenti. Per ciascuna ottieni il tipo di evento, lo stato (pending, delivered o failed), lo stato HTTP restituito dal tuo server, il tempo di risposta, i tentativi utilizzati su 3, quando è stata creata e completata, il prossimo orario di retry per quelle in sospeso, l'ultimo errore e il payload completo inviato.

Ogni consegna completata o fallita ha un pulsante Retry. Accoda di nuovo la stessa consegna (con lo stesso ID X-Webhook-Delivery, firmata di nuovo) con un nuovo budget di 3 tentativi. Tramite l'API, GET /v1/workspaces/{workspace_id}/webhooks/{id}/deliveries scorre le consegne precedenti con limit (fino a 100) e offset, mentre POST .../deliveries/{delivery_id}/retry esegue la stessa operazione del pulsante. Se non riesci a riprodurre una consegna autonomamente, l'assistenza Elido può riprodurla per te.

La registrazione nel log del body della risposta del tuo server è pianificata.

Test locale

È pianificato un comando CLI che inoltra i webhook a localhost (npx @elido/cli webhooks forward). Fino ad allora, rendi accessibile il tuo server locale tramite un tunnel come ngrok o Cloudflare Tunnel, aggiungi l'URL HTTPS del tunnel come endpoint e rimuovilo quando hai finito.

Limiti

  • 10 secondi per rispondere dal tuo endpoint.
  • 3 tentativi di consegna per evento, più i retry manuali.
  • L'API del log di consegna restituisce al massimo 100 consegne per pagina.

Risoluzione dei problemi

La firma non corrisponde mai. Le cause più comuni sono: il tuo framework ha analizzato e serializzato di nuovo il JSON prima che tu lo sottoponessi a hashing (usa il body raw), hai rimosso il prefisso whsec_ dalla chiave oppure hai firmato usando il timestamp del body invece dell'header X-Webhook-Timestamp. Il post sulla verifica delle firme contiene un test vector con cui confrontare il tuo codice.

La firma ha smesso di corrispondere dopo una rotazione. Il tuo server usa ancora il secret precedente. Distribuisci quello nuovo. Per un endpoint creato prima del 22 settembre 2026, la prima rotazione non include X-Elido-Signature-Previous su cui ripiegare.

Alcuni eventi arrivano due volte. Elido ha ritentato perché il tuo endpoint ha risposto con un errore o ha impiegato più di 10 secondi. Elimina i duplicati usando X-Webhook-Delivery e rispondi con un 2xx prima di eseguire operazioni lente.

Un tipo di evento non arriva mai. Controlla che l'endpoint sia sottoscritto a quel tipo, non sia in pausa e che il tipo sia presente nel catalogo sopra. I tipi contrassegnati come pianificati non vengono ancora inviati.

Ti è stato utile?
Hai bisogno di altro? Scrivi al team - risposta entro un giorno lavorativo.Contatta il supporto