{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "SupaTrust webhook events",
  "description": "SupaTrust が送る webhook の payload。type で data の形が決まる。未知のフィールド・未知の値は無視する",
  "anyOf": [
    {
      "$ref": "#/$defs/VerificationApproved"
    },
    {
      "$ref": "#/$defs/VerificationRejected"
    },
    {
      "$ref": "#/$defs/VerificationNeedsReview"
    },
    {
      "$ref": "#/$defs/VerificationExpired"
    },
    {
      "$ref": "#/$defs/VerificationFailed"
    }
  ],
  "$defs": {
    "SessionRef": {
      "type": "object",
      "properties": {
        "sessionId": {
          "type": "string",
          "description": "セッション ID(`vs_` + 32 桁の 16 進)",
          "examples": ["vs_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^vs_[0-9a-f]{32}$"
            }
          ]
        },
        "tenantId": {
          "type": "string",
          "description": "テナント ID(`tn_` + 32 桁の 16 進)",
          "examples": ["tn_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^tn_[0-9a-f]{32}$"
            }
          ]
        }
      },
      "required": ["sessionId", "tenantId"],
      "additionalProperties": true
    },
    "ReviewSummary": {
      "type": "object",
      "properties": {
        "reviewedAt": {
          "type": "string",
          "description": "手動レビューが確定した日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "note": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "レビューのメモ(自由記述)。無ければ null。個人情報を含みうるのでログに出さない。個人情報の消去後は null"
        }
      },
      "required": ["reviewedAt", "note"],
      "additionalProperties": true
    },
    "DocumentCheckSummary": {
      "type": "object",
      "properties": {
        "performed": {
          "type": "boolean",
          "description": "書類の確認を実施したか"
        },
        "documentType": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "確認した書類の種類(利用者が選んだもの。自動判別はしない)。選ばれていなければ null",
          "examples": ["drivers_license"]
        },
        "authenticity": {
          "anyOf": [
            {
              "type": "string",
              "enum": ["authentic", "suspicious", "unknown"]
            },
            {
              "type": "null"
            }
          ],
          "description": "書類の真正性の評価。authentic = 疑わしい点なし / suspicious = 疑わしい点あり / unknown = 疑わしい点なしとは判断できなかった(評価が無い・不十分)。unknown を承認の根拠にしない。未評価は null"
        }
      },
      "required": ["performed", "documentType", "authenticity"],
      "additionalProperties": true
    },
    "SelfieCheckSummary": {
      "type": "object",
      "properties": {
        "performed": {
          "type": "boolean",
          "description": "顔の確認を実施したか"
        },
        "livenessConfidence": {
          "anyOf": [
            {
              "type": "number",
              "allOf": [
                {
                  "minimum": 0,
                  "maximum": 1
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "生存確認(本人がその場にいるか)の確からしさ(0〜1)。値が無ければ null"
        },
        "faceMatchConfidence": {
          "anyOf": [
            {
              "type": "number",
              "allOf": [
                {
                  "minimum": 0,
                  "maximum": 1
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "顔照合の確からしさ(0〜1)。値が無ければ null"
        }
      },
      "required": ["performed", "livenessConfidence", "faceMatchConfidence"],
      "additionalProperties": true
    },
    "InputMatchSummary": {
      "type": "object",
      "properties": {
        "performed": {
          "type": "boolean",
          "description": "入力情報の照合を実施したか"
        },
        "matched": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "description": "照合できた項目がすべて一致したら true。照合できた項目が無ければ null"
        },
        "fields": {
          "anyOf": [
            {
              "type": "object",
              "additionalProperties": {
                "type": "boolean"
              }
            },
            {
              "type": "null"
            }
          ],
          "description": "項目ごとの一致(true / false)。値そのもの(個人情報)は含まない。未知のキーは無視する",
          "examples": [
            {
              "name": true,
              "birthDate": true,
              "address": false
            }
          ]
        }
      },
      "required": ["performed", "matched", "fields"],
      "additionalProperties": true
    },
    "VerificationOutcome": {
      "type": "object",
      "properties": {
        "session": {
          "$ref": "#/$defs/SessionRef"
        },
        "verdict": {
          "type": "string",
          "enum": ["approved", "rejected", "needs_review"],
          "description": "判定。approved = 承認 / rejected = 否認 / needs_review = 手動レビュー待ち(レビューが確定すると approved か rejected の通知が別の id でもう 1 回届く)"
        },
        "decidedAt": {
          "type": "string",
          "description": "判定が確定した日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "source": {
          "type": "string",
          "enum": ["automatic", "manual_review"],
          "description": "判定の出どころ。automatic = 自動判定 / manual_review = 手動レビュー"
        },
        "review": {
          "anyOf": [
            {
              "$ref": "#/$defs/ReviewSummary"
            },
            {
              "type": "null"
            }
          ],
          "description": "手動レビューの記録。source が manual_review のときだけ入り、それ以外は null"
        },
        "checks": {
          "type": "object",
          "properties": {
            "document": {
              "anyOf": [
                {
                  "$ref": "#/$defs/DocumentCheckSummary"
                },
                {
                  "type": "null"
                }
              ],
              "description": "書類の確認の要約。このセッションの手順に無ければ null"
            },
            "selfie": {
              "anyOf": [
                {
                  "$ref": "#/$defs/SelfieCheckSummary"
                },
                {
                  "type": "null"
                }
              ],
              "description": "顔の確認の要約。このセッションの手順に無ければ null"
            },
            "inputMatch": {
              "anyOf": [
                {
                  "$ref": "#/$defs/InputMatchSummary"
                },
                {
                  "type": "null"
                }
              ],
              "description": "入力情報の照合の要約。実施していなければ null"
            }
          },
          "required": ["document", "selfie", "inputMatch"],
          "additionalProperties": true,
          "description": "実施した確認の要約。個人情報は含まない"
        },
        "reasons": {
          "type": "array",
          "items": {
            "type": "string",
            "description": "理由コード。語彙は増えるので、未知の値は無視する",
            "allOf": [
              {
                "minLength": 1
              }
            ]
          },
          "description": "否認・要レビューの理由コード。語彙は増えるので、未知の値は無視する"
        }
      },
      "required": ["session", "verdict", "decidedAt", "source", "review", "checks", "reasons"],
      "additionalProperties": true
    },
    "VerificationApproved": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "webhook のイベント ID(`evt_` + 32 桁の 16 進 — ヘッダ webhook-id と同じ値)。再送でも変わらないので、重複を除くキーに使う",
          "examples": ["evt_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^evt_[0-9a-f]{32}$"
            }
          ]
        },
        "apiVersion": {
          "type": "string",
          "enum": ["2026-08-02"],
          "description": "payload の形のバージョン(日付)。同じバージョンの中でもフィールドは増えるので、未知のフィールドは無視する"
        },
        "createdAt": {
          "type": "string",
          "description": "イベントの作成日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "metadata": {
          "anyOf": [
            {
              "type": "object",
              "description": "自社側の相関用に渡す任意の JSON オブジェクト(自社のユーザー ID など)。JSON にして 8192 バイトまで。webhook にもそのまま載るので個人情報を入れない",
              "examples": [
                {
                  "userId": "user_0001"
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "セッション作成時に渡した metadata。渡していなければ null。個人情報の消去後に再送されると null"
        },
        "type": {
          "type": "string",
          "enum": ["verification.approved"]
        },
        "data": {
          "$ref": "#/$defs/VerificationOutcome"
        }
      },
      "required": ["id", "apiVersion", "createdAt", "metadata", "type", "data"],
      "additionalProperties": true,
      "description": "承認が確定した(自動判定または手動レビュー)"
    },
    "VerificationRejected": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "webhook のイベント ID(`evt_` + 32 桁の 16 進 — ヘッダ webhook-id と同じ値)。再送でも変わらないので、重複を除くキーに使う",
          "examples": ["evt_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^evt_[0-9a-f]{32}$"
            }
          ]
        },
        "apiVersion": {
          "type": "string",
          "enum": ["2026-08-02"],
          "description": "payload の形のバージョン(日付)。同じバージョンの中でもフィールドは増えるので、未知のフィールドは無視する"
        },
        "createdAt": {
          "type": "string",
          "description": "イベントの作成日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "metadata": {
          "anyOf": [
            {
              "type": "object",
              "description": "自社側の相関用に渡す任意の JSON オブジェクト(自社のユーザー ID など)。JSON にして 8192 バイトまで。webhook にもそのまま載るので個人情報を入れない",
              "examples": [
                {
                  "userId": "user_0001"
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "セッション作成時に渡した metadata。渡していなければ null。個人情報の消去後に再送されると null"
        },
        "type": {
          "type": "string",
          "enum": ["verification.rejected"]
        },
        "data": {
          "$ref": "#/$defs/VerificationOutcome"
        }
      },
      "required": ["id", "apiVersion", "createdAt", "metadata", "type", "data"],
      "additionalProperties": true,
      "description": "否認が確定した"
    },
    "VerificationNeedsReview": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "webhook のイベント ID(`evt_` + 32 桁の 16 進 — ヘッダ webhook-id と同じ値)。再送でも変わらないので、重複を除くキーに使う",
          "examples": ["evt_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^evt_[0-9a-f]{32}$"
            }
          ]
        },
        "apiVersion": {
          "type": "string",
          "enum": ["2026-08-02"],
          "description": "payload の形のバージョン(日付)。同じバージョンの中でもフィールドは増えるので、未知のフィールドは無視する"
        },
        "createdAt": {
          "type": "string",
          "description": "イベントの作成日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "metadata": {
          "anyOf": [
            {
              "type": "object",
              "description": "自社側の相関用に渡す任意の JSON オブジェクト(自社のユーザー ID など)。JSON にして 8192 バイトまで。webhook にもそのまま載るので個人情報を入れない",
              "examples": [
                {
                  "userId": "user_0001"
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "セッション作成時に渡した metadata。渡していなければ null。個人情報の消去後に再送されると null"
        },
        "type": {
          "type": "string",
          "enum": ["verification.needs_review"]
        },
        "data": {
          "$ref": "#/$defs/VerificationOutcome"
        }
      },
      "required": ["id", "apiVersion", "createdAt", "metadata", "type", "data"],
      "additionalProperties": true,
      "description": "自動判定の結果、手動レビュー待ちになった。レビューが確定すると approved か rejected が別の id でもう 1 回届く"
    },
    "ExpiredData": {
      "type": "object",
      "properties": {
        "session": {
          "$ref": "#/$defs/SessionRef"
        },
        "expiredAt": {
          "type": "string",
          "description": "期限切れになった日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        }
      },
      "required": ["session", "expiredAt"],
      "additionalProperties": true
    },
    "VerificationExpired": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "webhook のイベント ID(`evt_` + 32 桁の 16 進 — ヘッダ webhook-id と同じ値)。再送でも変わらないので、重複を除くキーに使う",
          "examples": ["evt_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^evt_[0-9a-f]{32}$"
            }
          ]
        },
        "apiVersion": {
          "type": "string",
          "enum": ["2026-08-02"],
          "description": "payload の形のバージョン(日付)。同じバージョンの中でもフィールドは増えるので、未知のフィールドは無視する"
        },
        "createdAt": {
          "type": "string",
          "description": "イベントの作成日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "metadata": {
          "anyOf": [
            {
              "type": "object",
              "description": "自社側の相関用に渡す任意の JSON オブジェクト(自社のユーザー ID など)。JSON にして 8192 バイトまで。webhook にもそのまま載るので個人情報を入れない",
              "examples": [
                {
                  "userId": "user_0001"
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "セッション作成時に渡した metadata。渡していなければ null。個人情報の消去後に再送されると null"
        },
        "type": {
          "type": "string",
          "enum": ["verification.expired"]
        },
        "data": {
          "$ref": "#/$defs/ExpiredData"
        }
      },
      "required": ["id", "apiVersion", "createdAt", "metadata", "type", "data"],
      "additionalProperties": true,
      "description": "利用者が手続きを終えないまま、セッションの期限を過ぎた"
    },
    "FailedData": {
      "type": "object",
      "properties": {
        "session": {
          "$ref": "#/$defs/SessionRef"
        },
        "reason": {
          "type": "string",
          "description": "終了の理由の分類。語彙は増えるので、未知の値は無視する",
          "allOf": [
            {
              "minLength": 1
            }
          ]
        }
      },
      "required": ["session", "reason"],
      "additionalProperties": true
    },
    "VerificationFailed": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "webhook のイベント ID(`evt_` + 32 桁の 16 進 — ヘッダ webhook-id と同じ値)。再送でも変わらないので、重複を除くキーに使う",
          "examples": ["evt_00000000000000000000000000000001"],
          "allOf": [
            {
              "pattern": "^evt_[0-9a-f]{32}$"
            }
          ]
        },
        "apiVersion": {
          "type": "string",
          "enum": ["2026-08-02"],
          "description": "payload の形のバージョン(日付)。同じバージョンの中でもフィールドは増えるので、未知のフィールドは無視する"
        },
        "createdAt": {
          "type": "string",
          "description": "イベントの作成日時",
          "examples": ["2026-08-02T12:34:56.000Z"]
        },
        "metadata": {
          "anyOf": [
            {
              "type": "object",
              "description": "自社側の相関用に渡す任意の JSON オブジェクト(自社のユーザー ID など)。JSON にして 8192 バイトまで。webhook にもそのまま載るので個人情報を入れない",
              "examples": [
                {
                  "userId": "user_0001"
                }
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "セッション作成時に渡した metadata。渡していなければ null。個人情報の消去後に再送されると null"
        },
        "type": {
          "type": "string",
          "enum": ["verification.failed"]
        },
        "data": {
          "$ref": "#/$defs/FailedData"
        }
      },
      "required": ["id", "apiVersion", "createdAt", "metadata", "type", "data"],
      "additionalProperties": true,
      "description": "回復できないエラーでセッションが終了した"
    }
  }
}
