Webhookエンドポイントを作成する

アプリまたはRESTでワークスペースのWebhookを登録し、署名付きイベントを検証して配信をテストします。再試行、エンドポイントの上限、シークレットのローテーション、削除にも対応します。

最終確認日

スクリーンショットは英語版の画面です。

クラウドストレージのWebhookを設定すると、公開HTTPS受信サーバーで署名付きJSON通知を受け取れます。dosyaはfile.uploaded、file.deleted、share.accessedに対応しています。エンドポイントは作成と同時に有効になるため、本番イベントに利用する前に受信サーバーとシークレットの非公開ストレージを用意してください。

アクセスと受信サーバーの要件

サーバーにアクティビティを送るワークスペースを選択してください。Webhookの管理にはワークスペースのメンバーシップとmanage_settingsが必要です。標準のオーナーと管理者のロール、およびその権限を付与されたカスタムロールが該当します。REST認証情報にはさらにフルアクセス、REST APIプロトコルへのアクセス、そのエンドポイントと互換性のあるワークスペースへの固定が必要です。読み取り専用またはアップロード専用キーではWebhookを管理できません。

受信URLはHTTPSを使用し、公開アクセス可能なアドレスに解決される必要があります。localhost、プライベートネットワークの移動先、許可されないアドレスは、作成後にDNSが変わった場合も含めて拒否されます。公開HTTPSの開発トンネルは移動先が検証に通れば使用できます。http://localhostは登録できません。

エンドポイントの上限は無効なものを含めてワークスペースあたり16件です。無料プランのユーザーは作成者ごとに、すべてのワークスペースで合計3件作成できます。ワークスペースの上限は無料プランの上限より先に確認されます。使用していないエンドポイントを削除する前に、配信履歴が必要か判断してください。

エンドポイントURLと説明されたイベントを入力し、無害なイベントを1件発生させて配信を確認するWebhookエンドポイント作成の手順。
エンドポイントURLと説明されたイベントを入力し、無害なイベントを1件発生させて配信を確認するWebhookエンドポイント作成の手順。スクリーンショットを原寸大で開く。

手順:アプリで作成する

  1. 目的のワークスペースを有効にして連携 → Webhookを開いてください。
  2. 新規エンドポイントを選択します。新しいWebhookエンドポイントにエンドポイントURLを入力してください。
  3. イベントでファイルをアップロードしました、ファイルを削除しました、共有へのアクセスのうち少なくとも1つを選択します。後で受信先を識別するのに役立つ場合は**説明(任意)**を追加してください。
  4. エンドポイントを作成を選択します。HTTPS以外のアドレスはURL must be a valid https:// address.で、イベントの選択が空の場合はSelect at least one event type.で拒否されます。
  5. 署名シークレットでコピーを選択し、ダイアログを閉じる前にwhsec_の値を受信側のシークレット設定に保存してください。再表示されません。
  6. エンドポイントカードに有効と購読イベント名が表示されることを確認します。テストイベントを送信を選択し、配信と受信側のログを確認してください。

テストボタンはdata.test: true、file_id: "test_file"、name: "test.txt"、size: 12を持つ合成のfile.uploadedイベントを送信します。実際のファイルは作成しません。エンドポイントが別のイベントだけを購読していてもこのテストは送られるため、受信側で意図どおりに処理してください。トーストの**テストイベントを送信しました。**はテストが開始されたことを示します。配信の成功と受信側の検証済みレコードで受信を確認してください。

RESTで登録してテストする

権限のあるフルアクセスキーをDOSYA_API_KEYに非公開で設定してください。ワークスペースと受信先の例を実際の値に置き換えます。

set -e
umask 077
curl --fail-with-body --silent --show-error \
  'https://api.dosya.dev/api/webhooks' \
  -H "Authorization: Bearer $DOSYA_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary '{
    "workspace_id": "REPLACE_WITH_WORKSPACE_ID",
    "url": "https://receiver.example.com/dosya",
    "events": ["file.uploaded"],
    "description": "File processing receiver"
  }' -o webhook-created.json

receiver.example.comは動作しないプレースホルダーです。201レスポンスにはok: trueと、id、workspace_id、url、events、description、active: 1、source、secret、created_atを含むwebhookが含まれます。webhook.secretは受信側の非公開設定にコピーし、APIキー欄には入れないでください。Webhook署名シークレットは送信されるイベントを検証するもので、REST認証トークンではありません。

シークレットを保存してからwebhook.idを読み、テストを送信します。

DOSYA_WEBHOOK_ID=$(python3 -c 'import json; print(json.load(open("webhook-created.json"))["webhook"]["id"])')
curl --fail-with-body --silent --show-error --request POST \
  "https://api.dosya.dev/api/webhooks/$DOSYA_WEBHOOK_ID/test" \
  -H "Authorization: Bearer $DOSYA_API_KEY"
curl --fail-with-body --silent --show-error \
  "https://api.dosya.dev/api/webhooks/$DOSYA_WEBHOOK_ID/deliveries?page=1&per_page=10" \
  -H "Authorization: Bearer $DOSYA_API_KEY"

テストレスポンスはdelivery_idを返します。このレスポンスの時点では配信がまだ実行中の場合があります。一覧にはステータス、試行回数、レスポンスコード、記録されたエラーが表示されます。1回だけ表示されるシークレットの保存後、webhook-created.jsonを削除してください。GET /api/webhooks?workspace_id=…はシークレットを公開せずにエンドポイントを一覧表示します。

受信した各リクエストを検証する

受信側はContent-Type: application/json、User-Agent: dosya-webhooks/1と次のヘッダーを含むHTTP POSTを受け取ります。

  • X-Dosya-Signature: t=TIMESTAMP,v1=LOWERCASE_HEX_HMAC
  • X-Dosya-Event-Id:変わらないイベントID
  • X-Dosya-Event-Type:イベント名
  • X-Dosya-Delivery-Id:配信レコードID

JSONエンベロープにはid、type、Unix秒のcreated、workspace_id、dataがあります。ファイルのアップロードイベントはfile_id、name、バイト単位のsize、folder_id、version、is_new_versionを提供します。受信側への通知であり、ファイルのバイトデータやダウンロード権限は含まれません。

署名シークレットを使い、timestamp + "." + raw_bodyに対するHMAC-SHA256を検証してください。JSONを解析する前に元のリクエストのバイトデータを保持します。JSONの再シリアライズによって署名が変わる場合があります。定数時間で比較し、時刻との差が300秒を超えるタイムスタンプを拒否してください。次のNode.js検証関数は組み込みのcryptoのみを使用します。

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody must be a Buffer of the untouched HTTP request body.
export function verified(rawBody, signature, secret, now = Math.floor(Date.now() / 1000)) {
  const match = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(signature ?? '');
  if (!match || Math.abs(now - Number(match[1])) > 300) return false;
  const expected = createHmac('sha256', secret)
    .update(match[1] + '.').update(rawBody).digest();
  const received = Buffer.from(match[2], 'hex');
  return received.length === expected.length && timingSafeEqual(expected, received);
}

検証に成功してからイベントを解析し、キューに追加してください。業務処理を適用する前に、エンベロープのidをキーとする重複排除レコードを永続化します。自動再試行はイベントと配信の識別情報を保持し、手動再配信は同じイベントとペイロードに対して新しい配信IDを使用します。永続的な受け入れ前に2xxを返すと、その後失われる作業に応答したことになる可能性があります。

配信のタイミングと復旧

2xxレスポンスはすべて配信成功とみなされます。受信側のタイムアウトは10秒です。素早く受け入れ、長い処理を永続キューに移してください。2xx以外のレスポンス、タイムアウト、URL検証の問題は失敗した試行としてカウントされます。許可されたリダイレクトは1回までで、2回目は失敗します。リダイレクトの連鎖より直接の安定した受信URLのほうが診断しやすくなります。

試行は合計6回であり、最初の試行後に6回再試行するわけではありません。最初は即時に実行され、その後の失敗ごとの待機時間は直前の失敗から30秒、2分、10分、1時間、6時間です。スケジュールやネットワーク処理によって遅延が加わるため、配信期限は保証されません。

エンドポイントはイベントをまたいで15回連続で試行が失敗すると自動的に無効化されます。試行が成功すると連続失敗のカウントはリセットされます。受信側を修正し、配信を確認してから、無効化されたカードの再度有効化を使用してください。再有効化すると失敗カウンターはクリアされます。問題が残ったまま再有効化しないでください。

保持された配信には、展開したログの再配信またはPOST /api/webhooks/{id}/deliveries/{delivery_id}/redeliverを使用してください。元のイベントIDとペイロードを保持した別の配信レコードが作成されます。通知を再試行してもジョブ、請求書、外部操作が重複しないよう、重複排除を維持してください。テストと再配信の各エンドポイントはユーザーごとに300秒あたり20回までです。429レスポンスのRetry-Afterに従ってください。

設定エラーと元に戻せない変更

問題対処
400、Endpoint URL not allowed: …HTTPS、DNS、または示されたアドレス検証の問題を修正してください。URLは登録時と配信時に確認されます。
400、events must be a non-empty array対応するイベント文字列を少なくとも1つ送信してください。
400、unknown event type: …file.uploaded、file.deleted、share.accessedを正確に使用してください。
403、API key scope 'full' required権限のあるフルアクセス認証情報を使用してください。ロールの変更だけでは制限付きキーの範囲は広がりません。
403、You don't have permission to manage webhooksワークスペース管理者にmanage_settingsを依頼してください。
400、Webhook endpoint limit reached (16 per workspace). Delete an unused endpoint first.無効なものも含め、ワークスペースのエンドポイントを確認してください。
403、The free plan allows 3 webhook endpoints in total. Delete one or upgrade for more.すべてのワークスペースで自分が作成したエンドポイントを確認してください。
404、Webhook not foundまたはDelivery not found再試行前にIDとエンドポイントの関連付けを確認してください。

シークレットをローテーションは新しい署名シークレットを生成し、猶予期間なしで古いシークレットを直ちに無効にします。受信側が代替値を速やかに受け入れられるよう準備し、新しく表示された値を保存して古いシークレットを削除してください。RESTでの対応操作はPOST /api/webhooks/{id}/roll-secretです。secretを1回返し、ユーザーごとに1時間あたり10回まで許可します。表示を逃した場合は再度ローテーションする必要があります。

編集ではURL、イベント、説明、有効状態を変更できます。削除は確認を求め、エンドポイントと配信履歴を完全に削除します。元に戻すことはできません。削除すると以後そのエンドポイントへの配信は停止しますが、別のサーバーがすでに受信したイベントやデータは回収できません。

受信側のレスポンスの一部はログに最大500文字保持される場合があります。認証情報や機密データを含まない短い応答を返してください。シークレット、署名、機密性のあるペイロード全体ではなく、イベントID、配信ID、機密情報を除いたエラーをログに記録します。合成テストの後、本番の後続処理を有効にする前に、購読している無害な実イベントを送信し、1回だけ受け入れられたことを確認してください。

期待される結果

エンドポイントが選択したワークスペースで有効になり、受信側が署名を検証してイベントレコードを1件永続化します。配信一覧には合成テストと無害な購読イベントの成功が表示されます。エンドポイントのシークレットは受信側で非公開に保持され、エンドポイント一覧には表示されません。

関連ガイド

この記事は役に立ちましたか?

評価の結果を読み込んでいます…

投票すると、回答を変更できるように、必要な投票用Cookieが最長180日間保存されます。

質問と回答

このガイドの手順について質問できます。質問は確認後に公開されます。

公開の質問には、アカウントの詳細、認証情報、非公開ファイルを含めないでください。これらについては 非公開サポート をご利用ください。

質問を読み込んでいます…

    dosyaアカウントにサインインすると、質問を投稿できます。

    やり直す前に結果を確認

    操作をもう一度確認する必要があるときは、次の共通の確認事項をご利用ください。