エージェントイベントのWebhookを設定する
エージェントのジョブが完了または失敗したとき、エージェントが承認待ちになったとき、あるいはドキュメントサイトが公開されたときに、独自のhttpsエンドポイントで署名付きPOSTを受け取ります。イベント、ペイロード、署名の検証、再試行、自動無効化について説明します。
Webhookは、エージェントのジョブ完了や承認待ちなど、何らかのイベントが発生した瞬間に、署名付きのPOSTを独自のエンドポイントへ送信するため、システム側でポーリングを行う必要がありません。この記事では、エンドポイントの追加、イベント、ペイロード、署名の検証、および配信が失敗した場合の動作について解説します。
始める前に
- WebhookはPro、Business、およびCustomプランで利用可能です(「WebhookはProプラン以上で利用可能です」)。
- Webhookを管理できるのはワークスペースのオーナーと管理者のみです。 その他のメンバーには「オーナーと管理者のみがWebhookを管理できます」と表示されます。
- 10秒以内に
2xxステータスで応答する、公開されたhttpsアドレスが必要です。 - 1つのワークスペースにつき最大10個のWebhookを作成できます。
Webhookを追加する
Webhookタブを開く
ワークスペースメニューを開き、AI agents & APIを選択してから、Webhooksを開きます。新しいWebhookをクリックします。

各Webhookには、イベント、最終送信日時、シークレットの末尾が表示されます。 エンドポイントを入力する
- Endpoint URL: 「公開されたHTTPSアドレス」。例:
https://example.com/clevera/webhooks。 - 説明: 任意。最大200文字まで。例:「Slackリレー」。
- Endpoint URL: 「公開されたHTTPSアドレス」。例:
イベントを選択する
受信するイベントにチェックを入れるか、All events, including new ones(新しいイベントを含むすべてのイベント)を選択します。近日公開とマークされたイベントは受け付けられますが、「このイベントを送信するものはまだありません」と表示されます。

「近日公開」とマークされたイベントは受け付けられますが、まだ送信されません。 作成してシークレットを保存する
Create webhookをクリックします。Signing secret(
whsec_で始まります)が一度だけ表示されます:「今すぐコピーしてください。二度と表示されません。Clevera-Signatureヘッダーの確認に使用します」。パスワードのように保存してから、保存しましたをクリックします。テストイベントを送信する
Webhookの**⋯メニューを開き、テストイベントを送信を選択します。Cleveraは署名付きの
pingイベントを一度だけ送信します(再試行は行われません)。「テストイベントを送信しました」と表示されればCleveraから送信されています。エンドポイントの応答については配信**を確認してください。
イベント
| イベント | 送信タイミング |
|---|---|
job.started |
エージェントが開始したジョブが実行を開始したとき。 |
job.needs_input |
ジョブが承認などの人の対応を待っているとき。リンクとリクエストの有効期限が含まれます。 |
job.succeeded |
ジョブが完了したとき。 |
job.failed |
ジョブが失敗したとき。エラーコードが含まれます。 |
job.canceled |
ジョブがキャンセルされたか、承認が拒否または期限切れになったとき。 |
approval.requested |
エージェントがエージェントのリクエストで承認を求めたとき。 |
approval.decided |
誰かがリクエストを承認または拒否したか、期限切れになったとき。 |
site.published |
ドキュメントサイトが公開されたとき。 |
site.build_failed |
ドキュメントサイトの公開が失敗したとき。 |
ping |
テストイベントを送信をクリックしたとき。サブスクリプションは不要です。 |
以下のイベントは近日公開としてリストされており、まだ送信されません:job.progress、video.ready、article.ready、research.completed、insights.weekly。
ジョブイベントは、アプリ内でユーザーが開始した動画ではなく、エージェントが(APIトークンや接続されたアプリを通じて)開始したジョブを対象としています。
Cleveraが送信するもの
すべての配信は、JSONボディと以下のヘッダーを含むPOSTです:
| ヘッダー | 値 |
|---|---|
Content-Type |
application/json |
User-Agent |
Clevera-Webhooks/1.0 |
Clevera-Event |
job.succeeded のようなイベント名 |
Clevera-Delivery |
配信の一意のID。再配信では同じIDが繰り返されるため、重複の無視に使用してください。 |
Clevera-Signature |
t=<unix time>,v1=<signature> |
ペイロードにはID、リンク、ステータス、数値が含まれますが、コンテンツそのものは含まれません。完了した動画や記事を読み取るには、トークンを使用してAPIを呼び出してください。
{
"id": "6f1c2d3e-4b5a-4c6d-8e9f-0a1b2c3d4e5f",
"event": "job.succeeded",
"created_at": "2026-10-20T14:03:11Z",
"data": {
"job": {
"id": "job_8k2m4n6p8r0t2v4x",
"kind": "video.create",
"status": "succeeded",
"error_code": null,
"subject": { "type": "video", "id": "vid_example" },
"credits_spent": 64
},
"needs_input": null,
"workspace": { "id": "tm_example" }
}
}
{
"id": "0b9a8c7d-6e5f-4a3b-9c2d-1e0f9a8b7c6d",
"event": "approval.requested",
"created_at": "2026-10-20T14:01:02Z",
"data": {
"approval": {
"id": "apr_example",
"kind": "spend",
"status": "pending",
"credits_high": 80,
"expires_at": "2026-10-21T14:01:02Z",
"decided_at": null,
"url": "https://app.clevera.ai/agents?tab=requests&team=tm_example"
},
"job": { "id": "job_8k2m4n6p8r0t2v4x", "kind": "video.create" },
"workspace": { "id": "tm_example" }
}
}
署名を検証する
すべての配信は、信頼する前に確認してください。署名は、署名シークレットをキーとして使用したHMAC-SHA256であり、タイムスタンプ、ドット、および生のリクエストボディから生成されます:<t>.<body>。
Clevera-Signatureヘッダーからtとv1を読み取ります。HMAC-SHA256(secret, t + "." + rawBody)を16進数として計算します。- 定数時間で
v1と比較します。 - 取得されたリクエストの再送を防ぐため、
tが5分以上経過している配信は拒否します。
import crypto from 'node:crypto';
export function verifyClevera(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')));
const t = Number(parts.t);
if (!parts.v1 || !Number.isInteger(t)) return false;
if (Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return expected.length === parts.v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hashlib, hmac, time
def verify_clevera(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.strip().split("=", 1) for p in header.split(","))
t, v1 = parts.get("t", ""), parts.get("v1", "")
if not t.isdigit() or not v1 or abs(time.time() - int(t)) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, v1)
function verifyClevera(string $rawBody, string $header, string $secret, int $tolerance = 300): bool
{
parse_str(str_replace(',', '&', $header), $parts);
$t = $parts['t'] ?? '';
$v1 = $parts['v1'] ?? '';
if (! ctype_digit($t) || $v1 === '' || abs(time() - (int) $t) > $tolerance) {
return false;
}
return hash_equals(hash_hmac('sha256', $t.'.'.$rawBody, $secret), $v1);
}
ボディは受信したままの状態で使用してください。JSONを先に解析して再エンコードするとバイト列が変わり、署名が一致しなくなります。
再試行と失敗
エンドポイントが2xxステータスで応答した時点で、配信済みとみなされます。それ以外の場合は試行失敗となります:
- リダイレクトを含むその他のステータス(
3xxは追跡されません); - 10秒以内に応答がない(接続に5秒);
- 公開インターネット上で解決できないアドレス。
Cleveraは失敗した配信を5回再試行します(1分後、5分後、30分後、2時間後、6時間後)。エンドポイントの応答ボディは読み取られません。
15回連続で配信が失敗すると、Webhookはオフになります:「15回連続で配信に失敗したためオフになりました。エンドポイントを修正してからオンにしてください」。オーナーと管理者には「hostへのWebhookがオフになりました」という通知が届きます:「配信が失敗し続けました。エンドポイントを修正してから再度オンにしてください」。オフの間に発生したイベントは送信されません。テストイベントはこれにはカウントされません。
Webhookを管理する
Webhookの配信をクリックしてログを確認するか、**⋯**メニューからその他の操作を行います:
| オプション | 操作内容 |
|---|---|
| 編集 | URL、イベント、説明を変更します。 |
| 配信 | 最新の100件の配信状況(配信済み、失敗しました、送信中)、試行回数、HTTPコードを表示します。再配信で再度送信します。配信ログは30日間保持されます。 |
| テストイベントを送信 | 署名付きのpingを送信します。 |
| シークレットを再生成 | 「新しいシークレットで直ちに署名されます。エンドポイントを更新して確認してください」。重複期間はないため、直後にエンドポイントを更新してください。 |
| オフにする / オンにする | 配信を一時停止および再開します。 |
| 削除 | 「イベントの送信を停止し、配信ログを削除します。元に戻すことはできません」。 |
ワークスペースがProプランを終了した場合
Webhookはリストに残ったまま編集や削除が可能ですが、何も送信されません。再試行待ちの配信はplan_lockedで失敗として終了し、テストイベントを送信や再配信は「Webhookはプランに含まれていません」と表示されます。Proにアップグレードすると送信が再開され、何も削除されません。
トラブルシューティング
| メッセージ | 原因 | 解決策 |
|---|---|---|
| 「Webhookはプランに含まれていません。」 | ワークスペースがPro、Business、Customプランではありません。 | Proにアップグレードしてください。 |
| 「https://アドレスを使用してください。」 | URLがhttp://で始まっています。 |
エンドポイントをHTTPSで提供してください。 |
| 「IPアドレスではなくホスト名を使用してください。」 | URLにIPアドレスが使用されています。 | ドメイン名を使用してください。 |
| 「このアドレスは公開インターネット上で到達できません。」 | ホストがプライベートまたはローカルアドレスに解決されています。 | 公開エンドポイントまたはリレーを使用してください。 |
| 「アドレスからユーザー名とパスワードを削除してください。」 | URLにuser:password@が含まれています。 |
削除し、代わりに署名を確認してください。 |
| 「有効なWebアドレスを入力してください。」 | URLが無効です。 | 誤字を確認してください。 |
| 「少なくとも1つのイベントを選択してください。」 | イベントが選択されていません。 | 少なくとも1つ選択してください。 |
| 「このワークスペースには既に10個のWebhookがあります。」 | ワークスペースの制限です。 | 使用していないものを削除してください。 |
| 「先にWebhookをオンにしてください。」 | オフのWebhookで再配信を試みました。 | オンにしてから再配信してください。 |
| 「この配信はまだ送信中です。」 | 配信が再試行中です。 | 完了まで待ってください。 |
| 配信がHTTPコードで失敗する | エンドポイントがエラーを返しました。 | エンドポイントのログを確認し、2xxを迅速に返すようにしてください。時間のかかる処理は応答後に行ってください。 |
| 署名が一致しない | 確認前にボディが変更されたか、シークレットが古いです。 | 生のボディに対して検証してください。不明な場合はシークレットを再生成してください。 |