Webhooks: assine eventos de links e do workspace

Envie requisições HTTP POST assinadas do Elido para seu servidor quando links, domínios, membros e seu workspace mudarem. Cabeçalhos, payloads, novas tentativas, registro de entregas e rotação de segredo.

10 min de leituraAtualizado 2026-09-22

O que você vai configurar

  • Um endpoint que recebe eventos do Elido, como link.created, link.updated, link.deleted, member.invited e domain.verified.
  • Verificação HMAC-SHA256 do cabeçalho X-Elido-Signature, para que seu servidor possa confirmar que cada entrega veio do Elido.
  • Três tentativas de entrega por evento, um registro de entregas com um botão manual de Retry e rotação de segredo com uma sobreposição de 7 dias.

Os webhooks enviam eventos do Elido para seu servidor conforme acontecem, para que você não precise consultar a API repetidamente. Usos comuns: sincronizar metadados de links com um CRM, manter um índice interno de links atualizado ou iniciar um job quando um link é publicado.

Os webhooks abrangem alterações em links, domínios, membros e no workspace. Eles não transportam cliques individuais. Para dados de cliques, use a exportação de cliques ou uma integração de eventos, como o Mixpanel. Eventos de webhook por clique estão planejados.

Adicionar um endpoint de webhook

  1. Vá para Dashboard → Webhooks.
  2. Informe a URL para a qual devemos fazer o POST e uma descrição opcional.
  3. Escolha o tipo de endpoint: Events (você escolhe os tipos de evento) ou SIEM (firehose) (todos os eventos do workspace).
  4. Em um endpoint de Events, marque os tipos de evento desejados. Os eventos link.* vêm marcados por padrão.
  5. Clique em Add endpoint. O segredo de assinatura aparece uma vez, logo abaixo do formulário. Copie-o agora: o Elido não o mostrará novamente.

A URL deve ser HTTPS. URLs http:// simples são rejeitadas ao salvar o endpoint, exceto localhost e 127.0.0.1, que continuam permitidos para desenvolvimento local.

Você pode pausar e retomar um endpoint na lista. Um endpoint pausado não recebe novas entregas, e tudo o que ainda estiver na fila para esse endpoint aguardará até que você o retome.

Quem pode gerenciar webhooks

Qualquer pessoa no workspace pode visualizar os endpoints e o registro de entregas. Criar, editar, pausar, excluir, rotacionar o segredo e tentar entregar novamente exigem a permissão workspace.edit, que as funções integradas Admin e Owner possuem. Uma chave de API pode chamar os mesmos endpoints de webhook da API se sua função tiver essa permissão.

Tipos de endpoint

  • Events (event): recebe somente os tipos de evento aos quais você se inscreveu. Assinado.
  • SIEM (siem): recebe todos os eventos publicados para o workspace, incluindo audit.event para cada entrada do registro de auditoria. Assinado. Destinado a pipelines de logs e ferramentas de segurança.
  • Discord, Telegram e Sentry: canais de chat e alertas que reutilizam o mesmo sistema de entrega, mas enviam o formato de mensagem próprio do fornecedor. Eles se autenticam pela URL ou pelo token do fornecedor, portanto não carregam cabeçalhos de assinatura. Consulte Discord, Telegram e Sentry.

Tudo o que vem abaixo sobre assinaturas e segredos se aplica somente aos endpoints Events e SIEM.

Catálogo de eventos

Os nomes seguem <resource>.<action>. O formulário do dashboard oferece os mais comuns; pela API, você pode inscrever um endpoint Events em qualquer tipo desta lista, e um endpoint SIEM recebe todos eles.

No seletor do dashboard:

  • link.created: um link curto foi criado, incluindo links criados em massa.
  • link.updated: um link mudou (destino, título, tags, expiração e assim por diante), foi restaurado, teve o status alterado ou teve o status de segurança alterado pela moderação.
  • link.deleted: um link foi excluído de forma reversível.
  • workspace.updated: as configurações do workspace mudaram.
  • workspace.created: publicado quando um workspace é criado. Como nenhum endpoint pode existir em um workspace antes de sua criação, normalmente você não receberá este evento.
  • member.invited: alguém entrou no workspace por adição direta, aceitação de convite ou provisionamento SCIM.
  • member.removed: um membro foi removido manualmente ou pelo SCIM.
  • audit.event: um evento para cada entrada do registro de auditoria.

Disponíveis pela API ou por um endpoint SIEM:

  • link.expired: um link passou da data de expiração.
  • link.cap_reached: um link atingiu seu limite de cliques. data inclui cap e clicks.
  • link.broken: a verificação de integridade de links do Elido detectou que o destino está falhando. data inclui status_code, error_message e first_seen_at.
  • link.encrypted_created e link.encryption_rotated: para links criptografados.
  • domain.verified: um domínio personalizado passou na verificação de DNS.
  • domain.ssl_failed: os registros DNS de um domínio personalizado ainda não foram encontrados 24 horas depois de sua adição. Apesar do nome, isso diz respeito à verificação de DNS, não à renovação do certificado.
  • member.role_changed: a função de um membro mudou. data inclui old_role, new_role e changed_by_user_id.
  • invitation.created e invitation.accepted.
  • Eventos de cobrança: subscription.* (por exemplo, subscription.activated, subscription.renewed, subscription.canceled) e usage.threshold_80, usage.threshold_100.

Planejados e não enviados atualmente: link.clicked.aggregated (contagens de cliques por link e por janela), eventos por clique, conversion.recorded, domain.tls_renewed, qr.generated e um evento separado abuse.flagged. Atualmente, uma decisão de moderação sobre um link chega como link.updated com o novo abuse_status.

Estrutura do payload

Cada entrega assinada é um POST com Content-Type: application/json, User-Agent: Elido-Webhooks/1.0 e este 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 é o tipo do evento. Ele também está no cabeçalho X-Webhook-Event.
  • timestamp indica quando o evento aconteceu, em UTC.
  • data depende do evento. Para eventos link.*, é o objeto completo do link (o exemplo acima está resumido). Para os outros eventos, é um objeto pequeno com os IDs e campos listados no catálogo.
  • Os segredos nunca saem do Elido: campos como o hash da senha de um link ou um token de convite são removidos de data antes da entrega.

Ainda não há um campo id de evento no corpo; um ID por evento está planejado. Para idempotência, use o cabeçalho X-Webhook-Delivery, descrito abaixo.

Cabeçalhos e assinaturas

Cada entrega para um endpoint Events ou SIEM contém:

CabeçalhoValor
X-Elido-Signaturev1= seguido da assinatura HMAC-SHA256 em hexadecimal
X-Webhook-SignatureMesmo valor de X-Elido-Signature, mantido para integrações antigas
X-Webhook-TimestampHora Unix em segundos em que esta requisição foi assinada
X-Webhook-EventO tipo do evento, por exemplo link.created
X-Webhook-DeliveryO ID da entrega. Ele permanece igual nas novas tentativas da mesma entrega
X-Elido-Signature-PreviousSomente durante uma rotação de segredo: a mesma assinatura feita com a chave antiga

A assinatura é calculada assim:

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

A chave é toda a sua string secreta, incluindo o prefixo whsec_, usada como está. Assine os bytes brutos recebidos, não um objeto JSON serializado novamente, e compare em tempo constante. Um exemplo curto em 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 versões em Python e Go, um vetor de teste e os erros comuns, consulte como verificar assinaturas de webhook.

Rotacionar o segredo de assinatura

Abra o endpoint em Dashboard → Webhooks e clique em Rotate secret. O novo segredo whsec_ é exibido uma vez, e o Elido passa a assinar com ele a partir desse momento.

A chave antiga permanece válida durante uma janela de tolerância de 7 dias. Durante essa janela, cada entrega contém duas assinaturas: X-Elido-Signature com a chave nova e X-Elido-Signature-Previous com a antiga, para que um receptor que ainda não tenha feito a troca continue verificando. Aceite qualquer um dos cabeçalhos enquanto distribui o novo segredo.

Endpoints criados antes de 22 de setembro de 2026 são uma exceção: a primeira rotação deles não produz X-Elido-Signature-Previous, portanto o segredo original deixa de funcionar imediatamente. Implante o novo segredo logo após essa primeira rotação. Endpoints criados desde então assinam com as duas chaves desde a primeira rotação. A partir da segunda rotação, aplica-se a sobreposição de 7 dias.

Novas tentativas

Uma entrega falha com qualquer resposta que não seja 2xx, um erro de rede ou nenhuma resposta em até 10 segundos. Cada entrega recebe 3 tentativas no total:

  1. A primeira tentativa, alguns segundos após o evento.
  2. Uma nova tentativa cerca de 5 minutos após a primeira falha.
  3. Uma última tentativa cerca de 15 minutos após a segunda falha.

Se a terceira tentativa falhar, a entrega é marcada como failed e não recebe novas tentativas automáticas. O endpoint permanece ativo e novos eventos continuam sendo entregues. Seu endpoint pode ver a mesma entrega mais de uma vez (por exemplo, quando processou uma requisição, mas respondeu depois do tempo limite de 10 segundos), portanto elimine duplicatas usando X-Webhook-Delivery.

Registro de entregas

Abra um endpoint em Dashboard → Webhooks para ver suas 100 entregas mais recentes. Para cada uma, você recebe o tipo do evento, o status (pending, delivered ou failed), o status HTTP retornado pelo seu servidor, o tempo de resposta, as tentativas usadas de um total de 3, quando ela foi criada e concluída, o próximo horário de nova tentativa para as pendentes, o último erro e o payload completo enviado.

Qualquer entrega entregue ou com falha tem um botão Retry. Ele coloca a mesma entrega novamente na fila (com o mesmo ID X-Webhook-Delivery, assinada novamente) com um novo orçamento de 3 tentativas. Pela API, GET /v1/workspaces/{workspace_id}/webhooks/{id}/deliveries pagina pelas entregas antigas com limit (até 100) e offset, e POST .../deliveries/{delivery_id}/retry faz o mesmo que o botão. Se você não puder reproduzir uma entrega por conta própria, o suporte do Elido poderá reproduzi-la para você.

O registro do corpo da resposta do seu servidor está planejado.

Testes locais

Um comando de CLI que encaminha webhooks para localhost (npx @elido/cli webhooks forward) está planejado. Até lá, exponha seu servidor local por meio de um túnel, como ngrok ou Cloudflare Tunnel, adicione a URL HTTPS do túnel como endpoint e remova-a quando terminar.

Limites

  • 10 segundos para seu endpoint responder.
  • 3 tentativas de entrega por evento, além de novas tentativas manuais.
  • A API do registro de entregas retorna no máximo 100 entregas por página.

Solução de problemas

A assinatura nunca corresponde. As causas mais comuns são: seu framework analisou e serializou novamente o JSON antes de você calcular o hash (calcule o hash do corpo bruto), você removeu o prefixo whsec_ da chave ou está assinando com o timestamp do corpo em vez do cabeçalho X-Webhook-Timestamp. A publicação sobre verificação de assinaturas tem um vetor de teste para comparar com seu código.

A assinatura parou de corresponder após uma rotação. Seu servidor ainda tem o segredo antigo. Implante o novo. Em um endpoint criado antes de 22 de setembro de 2026, a primeira rotação não tem X-Elido-Signature-Previous para servir como alternativa.

Alguns eventos chegam duas vezes. O Elido tentou entregar novamente porque seu endpoint respondeu com um erro ou levou mais de 10 segundos. Elimine duplicatas usando X-Webhook-Delivery e responda com 2xx antes de executar trabalhos demorados.

Um tipo de evento nunca chega. Verifique se o endpoint está inscrito nele, não está pausado e se o tipo está no catálogo acima. Os tipos marcados como planejados ainda não são enviados.

Foi útil?
Precisa de mais? Escreva à equipa - resposta num dia útil.Contactar o suporte