Webhooks

webhook の URL を指定してエージェントを作成すると、Cursor はステータス変更を知らせるために HTTP POST リクエストを送るよ。今サポートしてるのは statusChange イベントだけで、エージェントが ERRORFINISHED の状態になったときに発生するよ。

Webhook の検証

Webhook リクエストが確実に Cursor からのものか確認するために、各リクエストに含まれる署名を検証してね:

Headers

各 Webhook リクエストには次のヘッダーが含まれるよ:
  • X-Webhook-Signature – 形式 sha256=<hex_digest> の HMAC-SHA256 署名
  • X-Webhook-ID – この配信の一意の識別子(ログに便利)
  • X-Webhook-Event – イベント種別(今は statusChange のみ)
  • User-Agent – 常に Cursor-Agent-Webhook/1.0

署名の検証

Webhook 署名を検証するには、期待される署名を算出して、受信した署名と比較しよう:
const crypto = require('crypto');

function verifyWebhook(secret, rawBody, signature) {
  const expectedSignature = 'sha256=' + 
    crypto.createHmac('sha256', secret)
          .update(rawBody)
          .digest('hex');
  
  return signature === expectedSignature;
}
import hmac
import hashlib

def verify_webhook(secret, raw_body, signature):
    expected_signature = 'sha256=' + hmac.new(
        secret.encode(),
        raw_body,
        hashlib.sha256
    ).hexdigest()
    
    return signature == expected_signature
署名を計算するときは、必ずパース前の生のリクエストボディを使ってね。

ペイロード形式

Webhook のペイロードは、次の構造の JSON として送信されるよ:
{
  "event": "statusChange",
  "timestamp": "2024-01-15T10:30:00Z",
  "id": "bc_abc123",
  "status": "FINISHED",
  "source": {
    "repository": "https://github.com/your-org/your-repo",
    "ref": "main"
  },
  "target": {
    "url": "https://cursor.com/agents?id=bc_abc123",
    "branchName": "cursor/add-readme-1234",
    "prUrl": "https://github.com/your-org/your-repo/pull/1234"
  },
  "summary": "Added README.md with installation instructions"
}
いくつかのフィールドは任意で、利用可能なときだけ含まれるよ。

ベストプラクティス

  • 署名を検証する – リクエストが Cursor からのものか確認するため、常に webhook の署名を検証する
  • 再試行を処理する – エンドポイントがエラーステータスコードを返した場合、webhook は再試行されることがある
  • すばやくレスポンスを返す – 可能な限り早く 2xx ステータスコードを返す
  • HTTPS を使う – 本番環境の webhook エンドポイントには常に HTTPS の URL を使う
  • 生のペイロードを保存する – デバッグや将来の検証のために、生の webhook ペイロードを保存する