Skip to main content
Webhooks

Webhook イベントを受信する

Webhook リクエストを検証し、複数回配信される可能性のあるイベントを確実に処理します。

Webhook は現在 Beta 機能です。API、フィールド、および動作は今後のバージョンで変更される可能性があります。

HTTP リクエスト

イベントが発生すると、Qoder Cloud Agents は Endpoint URL に HTTP POST リクエストを送信します。
POST /webhooks/qoder HTTP/1.1
Content-Type: application/json; charset=utf-8
User-Agent: QoderCloudAgents-Webhook/1.0
Webhook-ID: whe_01k1jbxexample
Webhook-Event-Type: forward.schedule_run.succeeded
Webhook-Timestamp: 1788253679
Webhook-Signature: v1,BASE64_HMAC_SHA256
Header説明
Webhook-IDイベント ID。再試行時も同じ値を維持し、コンシューマーの冪等性キーとして使用できます。
Webhook-Event-Typeイベントタイプ。
Webhook-Timestamp署名生成時の Unix 秒タイムスタンプ。
Webhook-Signatureリクエスト署名。現在の形式は v1,<base64>
任意の 2xx レスポンスが処理成功を示します。署名を検証してイベントを信頼できるキューに書き込み、速やかにレスポンスを返してください。

イベント構造

Forward のビジネスイベントは共通の envelope を使用します。
{
  "type": "event",
  "id": "whe_01k1jbxexample",
  "created_at": "2026-09-01T09:07:59Z",
  "data": {
    "type": "forward.schedule_run.succeeded",
    "source": "tool",
    "source_session_id": "sess_origin",
    "id": "srun_01k1jbrexample",
    "schema_version": 1,
    "run_id": "srun_01k1jbrexample",
    "schedule_id": "sched_01k1jbqexample",
    "identity_id": "idn_01k1jbnexample",
    "template_id": "tmpl_01k1jbmexample",
    "status": "completed",
    "trigger_type": "schedule",
    "attempt": 1,
    "push_status": "succeeded",
    "duration_ms": 15432
  }
}
フィールド説明
typestring常に event
idstringWebhook イベント ID。Webhook-ID と一致します。
created_atstringイベント発生日時。RFC 3339 形式。
data.typestringイベントタイプ。Webhook-Event-Type と一致します。
data.idstringイベントが発生したリソース ID。
data.schema_versionintegerイベントデータのバージョン。現在は 1
今後の拡張との互換性を保つため、認識できない新しいフィールドは無視してください。

Schedule イベント

以下の 3 種類の Schedule イベントの data には、sourcesource_session_id が含まれます。意味は Schedule の作成元を参照してください。Run イベントは親 Schedule の作成元を継承します。 サービスのデプロイ後に新たにキューに入ったイベントには、常に両フィールドが含まれます。過去のイベントやその再試行では欠落する場合があるため、クライアントはフィールドの欠落に対応してください。必要に応じてスケジュールを取得するまたはスケジュール実行を取得するで作成元を確認できます。

forward.schedule.created

Schedule が正常に作成されたときに送信されます。
{
  "type": "event",
  "id": "whe_01k1jbxcreated",
  "created_at": "2026-09-01T09:00:00Z",
  "data": {
    "type": "forward.schedule.created",
    "source": "api",
    "source_session_id": null,
    "id": "sched_01k1jbqexample",
    "schema_version": 1,
    "schedule_id": "sched_01k1jbqexample",
    "identity_id": "idn_01k1jbnexample",
    "template_id": "tmpl_01k1jbmexample",
    "status": "active",
    "trigger_policy_type": "cron",
    "next_trigger_at": "2026-09-02T01:00:00Z"
  }
}
trigger_policy_typenext_trigger_at は、対応する値がある場合にのみ返されます。

forward.schedule_run.succeeded

Schedule Run が正常に完了したときに送信されます。data.statuscompleted です。

forward.schedule_run.failed

Schedule Run が失敗したときに送信されます。構造は成功イベントと同じで、data.statusfailed となり、error_type が含まれる場合があります。
{
  "type": "event",
  "id": "whe_01k1jbxfailed",
  "created_at": "2026-09-01T09:07:59Z",
  "data": {
    "type": "forward.schedule_run.failed",
    "source": "tool",
    "source_session_id": "sess_origin",
    "id": "srun_01k1jbrfailed",
    "schema_version": 1,
    "run_id": "srun_01k1jbrfailed",
    "schedule_id": "sched_01k1jbqexample",
    "identity_id": "idn_01k1jbnexample",
    "template_id": "tmpl_01k1jbmexample",
    "status": "failed",
    "trigger_type": "schedule",
    "attempt": 1,
    "push_status": "failed",
    "duration_ms": 1200,
    "error_type": "runtime_error"
  }
}
業務結果は対応する Schedule Run 取得 API を正としてください。Webhook は状態変更を通知するためのものです。

Managed Agents リソースイベント

Forward では、Session、Session Thread、Agent、Environment、Memory Store、Vault、Vault Credential のイベントも購読できます。完全なイベント名とトリガーはサポート対象の公開イベントを参照してください。 これらのイベントは同じ外側の envelope を使用しますが、data にはリソース参照のみが含まれ、Schedule イベントの schema_version、業務ステータス、結果本文は含まれません。たとえば、セッションがアイドル状態になった場合は次のようになります。
{
  "type": "event",
  "id": "whe_01k1jbxidled",
  "created_at": "2026-09-01T09:07:59Z",
  "data": {
    "type": "session.status_idled",
    "id": "sess_01k1jbsexample"
  }
}
イベントの分類data.id追加フィールド
session.status_*session.updatedsession.deletedSession IDなし。
session.thread_*所属する Session IDsession_thread_id:個々のスレッド ID。
agent.*Managed Agent IDなし。
environment.*Environment IDなし。
memory_store.*Memory Store IDなし。
vault.*Vault IDなし。
vault_credential.*Vault Credential IDvault_id:所属する Vault の ID。
表内の * は分類のためだけに使用しており、events に指定できる前方一致ワイルドカードではありません。通知を受け取ったら、リソース ID で最新の詳細を取得できます。削除イベントに対応するリソースは、すでに取得できない場合があります。session.status_idled は業務処理の成功を意味しないため、セッションの出力とステータスを併せて判断してください。 webhook.test は上記のリソースイベント構造を使用しません。テストペイロードはテストイベントを送信するを参照してください。

署名を検証する

Endpoint 作成時に返される signing_secret を使用してリクエスト署名を検証します。署名対象は次の 3 つの要素を連結したものです。
signed_content = Webhook-ID + "." + Webhook-Timestamp + "." + raw_body
解析や再シリアライズを行う前の生のリクエストボディを使用してください。 Python の例:
import base64
import hashlib
import hmac
import time


def verify_webhook(
    secret: str,
    webhook_id: str,
    timestamp: str,
    signature_header: str,
    raw_body: bytes,
    tolerance_seconds: int = 300,
) -> bool:
    if not secret.startswith("whsec_"):
        return False

    try:
        ts = int(timestamp)
        key = base64.b64decode(secret[len("whsec_"):], validate=True)
    except (ValueError, TypeError):
        return False

    if abs(int(time.time()) - ts) > tolerance_seconds:
        return False

    signed_content = (
        webhook_id.encode()
        + b"."
        + timestamp.encode()
        + b"."
        + raw_body
    )
    expected = base64.b64encode(
        hmac.new(key, signed_content, hashlib.sha256).digest()
    ).decode()

    signatures = [
        value.removeprefix("v1,")
        for value in signature_header.split()
        if value.startswith("v1,")
    ]
    return any(hmac.compare_digest(expected, value) for value in signatures)
次の点も検証してください。
  1. Webhook-Timestamp と現在時刻の差が 5 分以内であること。
  2. Webhook-Signature に検証成功する v1 署名が 1 つ以上含まれること。
  3. 処理済みの Webhook-ID で副作用のある業務処理を再実行しないこと。

リトライと冪等性

Webhook は少なくとも 1 回配信されます。ネットワーク障害、タイムアウト、または非 2xx レスポンス時には、同じイベントが再試行される場合があります。
  • Webhook-ID で重複を排除してください。到着時刻から冪等性キーを生成しないでください。
  • 同じ Webhook-ID の重複リクエストには成功を返し、副作用を繰り返さないでください。
  • 処理失敗時は非 2xx を返します。処理成功時、またはすでに処理済みの場合は 2xx を返します。

関連