リンクとワークスペースのイベントを購読するWebhook

リンク、ドメイン、メンバー、ワークスペースに変更があったとき、Elidoから署名付きHTTP POSTをサーバーに送信します。ヘッダー、ペイロード、リトライ、配信ログ、シークレットローテーションについて説明します。

読了 2 分更新 2026-09-22

設定すること

  • link.created、link.updated、link.deleted、member.invited、domain.verifiedなどのElidoイベントを受け取るエンドポイント。
  • X-Elido-SignatureヘッダーをHMAC-SHA256で検証し、各配信がElidoから送られたことをサーバーで確認します。
  • イベントごとの3回の配信試行、手動のRetryボタンを備えた配信ログ、7日間の重複期間を設けたシークレットローテーション。

Webhookはイベントの発生時にElidoからサーバーへプッシュするため、APIをポーリングする必要がありません。一般的な用途には、リンクのメタデータをCRMに同期すること、リンクの内部インデックスを最新に保つこと、リンクが公開されたときにジョブを開始することなどがあります。

Webhookはリンク、ドメイン、メンバー、ワークスペースの変更を扱います。個々のクリックは含まれません。クリックデータにはクリックエクスポートまたはMixpanelなどのイベントインテグレーションを使用してください。クリックごとのWebhookイベントは提供予定です。

Webhookエンドポイントを追加する

  1. Dashboard → Webhooks に移動します。
  2. POST先のURLと、任意の説明を入力します。
  3. エンドポイントの種類として、Events(イベント種別を選択)または SIEM (firehose)(ワークスペース内のすべてのイベント)を選択します。
  4. Eventsエンドポイントの場合は、必要なイベント種別にチェックを入れます。link.*イベントにはデフォルトでチェックが入っています。
  5. Add endpoint をクリックします。署名シークレットはフォームのすぐ下に一度だけ表示されます。Elidoでは再表示できないため、ここでコピーしてください。

URLはHTTPSである必要があります。プレーンなhttp:// URLはエンドポイントを保存すると拒否されますが、localhostと127.0.0.1はローカル開発用として引き続き許可されます。

エンドポイントは一覧から一時停止・再開できます。一時停止したエンドポイントには新しい配信は送られず、キューに残っているものは再開するまで待機します。

Webhookを管理できるユーザー

ワークスペース内の全員がエンドポイントと配信ログを閲覧できます。作成、編集、一時停止、削除、シークレットのローテーション、配信の再試行にはworkspace.edit権限が必要です。この権限は組み込みの Admin と Owner ロールが持っています。APIキーも、そのロールにこの権限があれば、APIの同じWebhookエンドポイントを呼び出せます。

エンドポイントの種類

  • Events(event):購読したイベント種別のみを受け取ります。署名付きです。
  • SIEM(siem):audit.eventを含め、ワークスペースで公開されたすべてのイベントを受け取ります。署名付きです。ログパイプラインやセキュリティツール向けです。
  • Discord、Telegram、Sentry:同じ配信システムを再利用するチャット・アラートチャンネルですが、ベンダー独自のメッセージ形式で送信します。ベンダーのURLまたはトークンで認証するため、署名ヘッダーはありません。Discord、Telegram、Sentryを参照してください。

以下の署名とシークレットに関する説明は、EventsとSIEMエンドポイントにのみ適用されます。

イベントカタログ

名前は<resource>.<action>の形式です。ダッシュボードのフォームには最も一般的なものが表示されます。APIでは、この一覧にある任意の種別をEventsエンドポイントに購読させることができ、SIEMエンドポイントはすべてを受け取ります。

ダッシュボードの選択欄で利用できるもの:

  • link.created:一括作成されたリンクを含む、短縮リンクが作成された。
  • link.updated:リンク(遷移先、タイトル、タグ、有効期限など)が変更された、復元された、ステータスが変更された、またはモデレーションによって安全性ステータスが変更された。
  • link.deleted:リンクがソフトデリートされた。
  • workspace.updated:ワークスペースの設定が変更された。
  • workspace.created:ワークスペースの作成時に公開される。作成前のワークスペースにはエンドポイントを存在させられないため、通常は受信しません。
  • member.invited:直接追加、招待の承諾、SCIMプロビジョニングによって、誰かがワークスペースに参加した。
  • member.removed:手動またはSCIMによってメンバーが削除された。
  • audit.event:監査ログの各エントリにつき1件のイベント。

APIまたはSIEMエンドポイントで利用できるもの:

  • link.expired:リンクの有効期限が過ぎた。
  • link.cap_reached:リンクがクリック上限に達した。dataにはcapとclicksが含まれます。
  • link.broken:Elidoのリンクヘルスチェックで、遷移先に障害があることが検出された。dataにはstatus_code、error_message、first_seen_atが含まれます。
  • link.encrypted_createdとlink.encryption_rotated:暗号化されたリンク用です。
  • domain.verified:カスタムドメインがDNSチェックに合格した。
  • domain.ssl_failed:追加から24時間経ってもカスタムドメインのDNSレコードが見つからなかった。名前に反して、これは証明書の更新ではなくDNS検証に関するイベントです。
  • member.role_changed:メンバーのロールが変更された。dataにはold_role、new_role、changed_by_user_idが含まれます。
  • invitation.createdとinvitation.accepted。
  • 請求イベント:subscription.*(例:subscription.activated、subscription.renewed、subscription.canceled)およびusage.threshold_80、usage.threshold_100。

提供予定で、現在は送信されないもの:link.clicked.aggregated(ウィンドウごとのリンク別クリック数)、クリックごとのイベント、conversion.recorded、domain.tls_renewed、qr.generated、独立したabuse.flaggedイベント。現在、リンクに対するモデレーションの判定は、新しいabuse_statusを含むlink.updatedとして届きます。

ペイロードの形式

署名付きの各配信は、Content-Type: application/json、User-Agent: Elido-Webhooks/1.0を含むPOSTで、次のエンベロープを持ちます。

{
  "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はイベント種別です。X-Webhook-Eventヘッダーにも含まれます。
  • timestampはイベントが発生した時刻で、UTCです。
  • dataはイベントによって異なります。link.*イベントでは完全なリンクオブジェクトです(上の例は一部を省略しています)。その他のイベントでは、カタログに記載したIDとフィールドを含む小さなオブジェクトです。
  • シークレットがElidoの外に出ることはありません。リンクのパスワードハッシュや招待トークンなどのフィールドは、配信前にdataから削除されます。

現時点では本文にイベントidフィールドはありません。イベントごとのIDは提供予定です。冪等性には、後述するX-Webhook-Deliveryヘッダーを使用してください。

ヘッダーと署名

EventsまたはSIEMエンドポイントへの各配信には、次のヘッダーが含まれます。

HeaderValue
X-Elido-Signaturev1=に続く16進数のHMAC-SHA256署名
X-Webhook-SignatureX-Elido-Signatureと同じ値。古いインテグレーション向けに維持されています
X-Webhook-Timestampこのリクエストに署名した時点のUnix秒
X-Webhook-Eventイベント種別。例:link.created
X-Webhook-Delivery配信ID。同じ配信のリトライでは同じ値が維持されます
X-Elido-Signature-Previousシークレットローテーション中のみ。古いキーで作成した同じ署名

署名は次のように計算します。

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

キーにはwhsec_プレフィックスを含むシークレット文字列全体を、そのまま使用します。受信した生のバイト列に署名し、再シリアライズしたJSONオブジェクトには署名しないでください。比較には定時間比較を使用します。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);
  },
);

PythonとGoの例、テストベクター、よくある間違いについては、Webhook署名の検証方法を参照してください。

署名シークレットをローテーションする

Dashboard → Webhooks でエンドポイントを開き、Rotate secret をクリックします。新しいwhsec_シークレットが一度だけ表示され、それ以降、Elidoはそのシークレットで署名します。

古いキーは7日間の猶予期間中も有効です。この期間、各配信には2つの署名が含まれます。X-Elido-Signatureは新しいキー、X-Elido-Signature-Previousは古いキーで作成されるため、まだ切り替えていない受信側でも検証を続けられます。新しいシークレットを展開する間は、どちらのヘッダーも受け入れてください。

2026年9月22日より前に作成されたエンドポイントは例外です。最初のローテーションではX-Elido-Signature-Previousが生成されないため、元のシークレットは直ちに使えなくなります。その最初のローテーションの直後に、新しいシークレットをデプロイしてください。同日以降に作成されたエンドポイントでは、最初のローテーションから2つの署名が付与されます。2回目以降のローテーションでは、7日間の重複期間が適用されます。

リトライ

2xx以外のレスポンス、ネットワークエラー、または10秒以内にレスポンスがない場合、配信は失敗します。各配信の試行回数は合計3回です。

  1. 最初の試行は、イベントの数秒後に行われます。
  2. 最初の失敗から約5分後にリトライします。
  3. 2回目の失敗から約15分後に最後のリトライを行います。

3回目の試行も失敗すると、配信は failed とマークされ、自動では再試行されません。エンドポイントはアクティブなままで、新しいイベントは引き続き配信されます。エンドポイントがリクエストを処理したものの10秒のタイムアウト後に応答した場合など、同じ配信が複数回届くことがあります。そのため、X-Webhook-Deliveryで重複排除してください。

配信ログ

Dashboard → Webhooks でエンドポイントを開くと、直近100件の配信を確認できます。各配信について、イベント種別、ステータス(pending、delivered、failed)、サーバーが返したHTTPステータス、レスポンス時間、3回中の使用済み試行回数、作成・完了時刻、pendingの配信の次回リトライ時刻、最後のエラー、送信した完全なペイロードを確認できます。

deliveredまたはfailedの配信には Retry ボタンがあります。同じ配信を再びキューに入れます(X-Webhook-Delivery IDは同じで、新たに署名されます)。試行回数3回の新しい予算が適用されます。APIでは、GET /v1/workspaces/{workspace_id}/webhooks/{id}/deliveriesでlimit(最大100)とoffsetを使い、古い配信をページングできます。POST .../deliveries/{delivery_id}/retryはボタンと同じ処理を行います。自分で配信をリプレイできない場合は、Elidoサポートに依頼できます。

サーバーのレスポンスボディをログに記録する機能は提供予定です。

ローカルでテストする

Webhookをlocalhostへ転送するCLIコマンド(npx @elido/cli webhooks forward)は提供予定です。それまでは、ngrokやCloudflare Tunnelなどのトンネルを通じてローカルサーバーを公開し、そのトンネルのHTTPS URLをエンドポイントとして追加してください。完了したら削除してください。

制限

  • エンドポイントが応答するまでの時間は10秒です。
  • イベントごとに3回の配信試行があり、手動リトライを追加できます。
  • 配信ログAPIが1ページで返す配信は最大100件です。

トラブルシューティング

署名がまったく一致しない。 よくある原因は、フレームワークがハッシュ化する前にJSONを解析して再シリアライズしている(生の本文をハッシュ化してください)、キーからwhsec_プレフィックスを削除している、またはX-Webhook-Timestampヘッダーではなく本文のtimestampで署名していることです。署名検証の記事には、コードを照合できるテストベクターがあります。

ローテーション後に署名が一致しなくなった。 サーバーに古いシークレットが残っています。新しいシークレットをデプロイしてください。2026年9月22日より前に作成されたエンドポイントでは、最初のローテーションにフォールバック用のX-Elido-Signature-Previousがありません。

一部のイベントが2回届く。 エンドポイントがエラーで応答したか、10秒を超えて処理したため、Elidoがリトライしました。X-Webhook-Deliveryで重複排除し、時間のかかる処理を行う前に2xxを返してください。

あるイベント種別がまったく届かない。 エンドポイントがその種別を購読していて、一時停止されていないことを確認してください。また、その種別が上のカタログにあることも確認してください。提供予定と記載された種別はまだ送信されません。

役に立ちましたか?
もっと知りたいですか?チームにメールを - 1営業日以内に返信します。サポートに連絡