> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lymo.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook

> 処理完了時にイベントを受け取る

Lymo は [Svix](https://www.svix.com/) 経由で Webhook を配信します。各配信には、Svix SDK で検証可能な標準署名ヘッダーが付きます。

## 登録前に確認: ホスト名の許可リスト

Webhook の配信先は、**組織単位のホスト名許可リスト** でゲートされています。Svix 側の URL バリデーションに加えた多層防御で、API キーが漏洩した場合に Svix 経由で SSRF の踏み台にされることを防ぐ仕組みです。

<Warning>
  新規組織の既定の許可リストは **空** です。つまり、許可リストに配信先ホスト名を追加するまで、`POST /v1/webhooks` はすべて `422 invalid_webhook_url` で失敗します。統合作業を始める前に、Lymo の担当者（CSM・管理者）に `organization_settings.webhook_allowed_hostnames` への追加を依頼してください。
</Warning>

許可リストのルール:

* スキームは `https://` のみ。
* 完全一致: `webhook.site` は `webhook.site` のみを許可します。
* サブドメインのワイルドカード: `*.example.com` は `a.example.com`・`foo.bar.example.com` を許可しますが、**apex の `example.com` 自体は許可しません**。
* 大文字小文字は区別せず、punycode 形式で比較されます。

## エンドポイントを登録する

```bash theme={null}
curl -X POST "$LYMO_BASE/v1/webhooks" \
  -H "Authorization: Bearer $LYMO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.your-app.example.com/lymo",
    "events": ["video.analysis.completed"]
  }'
```

レスポンスに含まれる `secret`（`whsec_` で始まる）は、**作成時に必ず保存してください**。署名検証に必須であり、返却は作成時の 1 回のみです。現時点ではシークレットのローテーション用エンドポイントはありません。紛失・漏洩した場合は、エンドポイントを削除して作り直してください。

`events` を省略（または `[]` を指定）すると、すべてのイベント種別を購読します。

## イベント種別

| イベント                       | 状態        | トリガー                            |
| -------------------------- | --------- | ------------------------------- |
| `video.ready`              | 配信中       | 動画の処理が完了し、分析可能になったとき            |
| `video.analysis.completed` | 配信中       | `POST /analyses` ジョブが成功したとき     |
| `video.analysis.failed`    | 配信中       | `POST /analyses` ジョブが確定的に失敗したとき |
| `deal.scoring.completed`   | 未配信（配信予定） | `POST /scorings` ジョブが成功したとき     |
| `deal.scoring.failed`      | 未配信（配信予定） | `POST /scorings` ジョブが確定的に失敗したとき |

`deal.scoring.*` は、SDK の型を安定させる目的でスキーマには定義されていますが、配信側の実装はまだ入っていないため、現時点で購読しても通知は届きません。将来のリリースで有効化予定です。

各イベントのペイロードスキーマは **APIリファレンス** タブに記載があります。

## 署名検証

すべての配信には以下のヘッダーが付きます。

* `svix-id` — 配信ごとに一意な ID。再送でも変わりません。
* `svix-timestamp` — 送信時の Unix 秒。
* `svix-signature` — HMAC 署名。シークレットのローテーション中はスペース区切りで複数の署名が送られ、いずれか一致すれば検証成功となります（切り替え時の検証窓口確保のため）。

各言語の Svix SDK で検証してください。

```ts theme={null}
import { Webhook } from "svix";

const wh = new Webhook(process.env.LYMO_WEBHOOK_SECRET!);
const payload = wh.verify(rawBody, {
  "svix-id": req.headers["svix-id"] as string,
  "svix-timestamp": req.headers["svix-timestamp"] as string,
  "svix-signature": req.headers["svix-signature"] as string,
});
```

検証に失敗したリクエストは拒否してください。`verify` には **生のリクエストボディ** を渡す必要があります。一度パースして再シリアライズした JSON では検証できません。

## 配信セマンティクス

* 受信の応答は任意の `2xx` ステータスで構いません。非 2xx やネットワーク失敗は指数バックオフで再試行されます。
* `svix-id` は再送間で安定するため、受信済み ID を保存して重複処理をスキップすれば、ハンドラを冪等にできます。
* 再試行スケジュール、タイムアウト、保持期間は Svix 側で管理されます。詳細は [Svix の配信ドキュメント](https://docs.svix.com/retries) を参照してください。

## 一覧取得と削除

```bash theme={null}
# 登録済みエンドポイントの一覧
curl "$LYMO_BASE/v1/webhooks" -H "Authorization: Bearer $LYMO_KEY"

# エンドポイントの削除
curl -X DELETE "$LYMO_BASE/v1/webhooks/ep_2abcXYZ12345" \
  -H "Authorization: Bearer $LYMO_KEY"
```

エンドポイント ID は Svix が発行し、`ep_` で始まります。削除は即時反映されます。配信中のイベントは完了しますが、以降の新規イベントは送られません。
