Claude Media
Claude organization webhooksで制限・BAN通知を受ける手順

Claude organization webhooksで制限・BAN通知を受ける手順

Anthropicがユーザープロファイルを制限・BANしたときと、その解除時にwebhookで通知を受ける設定手順。エンドポイント登録、署名検証、取りこぼしの埋め方、404の原因をまとめます。

Claude organization webhooksで制限・BAN通知を受ける手順

Organization webhooksは、Anthropicが自社組織のユーザープロファイルを制限またはBANしたときと、その制限・BANが終わったときに、指定したURLへ通知を送る仕組みです。登録と管理はAdmin APIの /v1/organizations/webhooks で行い、ベータヘッダーは webhooks-2026-10-07 です。

最初に押さえておく点があります。ドキュメント冒頭の注記には、イベント配信はまだ有効になっておらず、登録したエンドポイントには何も届かないと書かれています。エンドポイントの登録と、イベント形式に沿った受信側の実装までは今のうちに進められます。この記事はその範囲を、登録から運用までの順に並べます。

プロファイルの作り方と anthropic-user-profile-id ヘッダーの付け方はClaude APIのUser Profilesでエンドユーザーを識別する手順にあります。ここでは、プロファイルが作ってある前提で通知の受け方を扱います。

使い始める前に満たす条件

利用には、組織側の条件と認証情報の条件があります。

組織の条件は次の2つです。

  • Claude APIの組織で、organization webhooksが有効になっていること。有効化は、Anthropicのアカウントチームへの問い合わせで依頼します
  • HIPAA readinessが有効になっていないこと

認証情報は、次のいずれかを使います。

  • Admin APIキー
  • org:admin スコープのOAuthベアラートークン
  • ワークスペースに限定されていない、個人またはサービスアカウントのキー

権限にも差があります。組織のメンバーなら誰でもエンドポイントの一覧と詳細を見られますが、作成・変更・削除とシークレットの再発行ができるのは、admin・owner・primary ownerのロールだけです。Admin APIキーの扱いはClaude Admin APIキーの取得方法とスコープ選択で触れています。

受け取れるイベントは2種類

イベントの種類は2つで、どちらもプロファイルへの措置(enforcement action)に関するものです。

イベント発火する条件
user_profile.enforcement_action_opened発火する条件Anthropicがプロファイルに対する措置を開始した
user_profile.enforcement_action_resolved発火する条件措置が終わった。Anthropicが解除した場合と、expires_at の時刻が過ぎた場合の両方

プロファイルを削除すると、開いている措置は resolved イベントなしで終了します。削除を自分で行う運用では、削除のタイミングで自前の状態も閉じておく必要があります。

措置の種類は restriction(制限)と ban(BAN)です。開いている間、Anthropicはそのプロファイルのリクエストの一部または全部を拒否します。拒否の範囲は措置によって一部のこともあれば全部のこともあるため、通知を受けたら中身を取りに行って確かめる形になります。

イベントにはIDしか入っていない

届くイベントは、プロファイルの状態そのものを運びません。入っているのは、プロファイルIDと措置のIDだけです。

{
  "type": "event",
  "id": "whe_4f2a9c1e7b3d5a8f0e6c2b9d1a7f3e5c",
  "created_at": "2026-10-15T17:02:41Z",
  "data": {
    "type": "user_profile.enforcement_action_opened",
    "id": "uprof_011CZkZCu8hGbp5mYRQgUmz9",
    "enforcement_action_id": "enac_011CZkZEq4TnWb7xLfRgPm2v",
    "organization_id": "org_011CZkZBj9RsYd3wNcHvKq6t"
  }
}

data.id がプロファイルのID、data.enforcement_action_id が enac_ で始まる措置のIDです。何が起きたかを知るには、GET /v1/user_profiles/{id} でプロファイルを取得します。

取得したプロファイルの enforcement_actions に、開いている措置が並びます。各措置の項目は次のとおりです。

項目内容
type内容restriction または ban
id内容措置のID
reason内容理由。unsupported_region / fraud_or_abuse / high_harm / usage_policy_violation / account_compromise / unspecified のいずれか
action内容利用者が措置を解くためにできること。何もできないときは null
opened_at内容措置が開いた時刻
expires_at内容自動で終わる時刻。終了日がなければ null

プロファイル全体の要約が enforcement_status です。BANが開いている間は banned、それ以外の措置が1つでも開いていれば restricted、なければ unrestricted になります。見慣れない値が来たら restricted として扱うよう指示されています。同じ考え方が type・reason・action にもあり、未知の type は restriction、未知の reason は unspecified、未知の action は null として扱います。

action が null のときは、利用者側にできる解除の手段がありません。利用者向けの画面や通知文を作るなら、action が null の分岐と reason が unspecified の分岐を最初から用意しておくと、未知の値が来たときも落ちません。

順序は信用せず、取得した状態を正とする

Anthropicがイベントを送るのは、プロファイルに変更が反映された後です。そのため、取得したプロファイルにはそのイベントの変更か、それより新しい変更が映っています。

ただしイベントは遅れたり、順序が入れ替わったりすることがあります。届いた順にオン・オフを切り替える実装にすると、resolved が先に届いたあと opened が遅れて届いた場合に、実際は解除済みなのに制限中と判定してしまいます。イベントは「プロファイルを見直す合図」にとどめ、判定は取得した現在の状態で行います。

resolved の後は、解除された措置が enforcement_actions から消えます。取得が 404 を返したら、プロファイルは削除されています。

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

登録は、POST /v1/organizations/webhooks にURLと購読するイベントを渡すだけです。リクエストには毎回 anthropic-beta: webhooks-2026-10-07 ヘッダーを付けます。SDKとCLIは、このヘッダーを自動で付けます。

curl "https://api.anthropic.com/v1/organizations/webhooks" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: webhooks-2026-10-07" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://example.com/anthropic-webhooks",
    "name": "Enforcement actions",
    "enabled_events": [
      "user_profile.enforcement_action_opened",
      "user_profile.enforcement_action_resolved"
    ]
  }'

ANTHROPIC_API_KEY には、Admin APIキーを入れます。CLIなら ant beta:organization:webhooks create に --url・--name・--enabled-event を渡す形で同じ登録ができます。

レスポンスには、エンドポイントの項目に加えて signing_secret が含まれます。このシークレットが返るのは、エンドポイントを作ったときとシークレットを再発行したときのレスポンスだけです。取りこぼすと確認する手段がないので、受け取ったらその場で秘匿情報の置き場に保存します。

エンドポイントの主な項目は次のとおりです。

項目内容
id内容wep_ で始まるID。Anthropicが付ける
url内容送信先。HTTPSのポート443、公開ドメイン名が必須でIPアドレスは不可。有効なエンドポイント同士でURLを重複させられない
enabled_events内容受け取るイベント。作成時は1つ以上が必要
name / description内容自分用のラベルと説明。省略可
state内容enabled または disabled
disabled_reason内容Anthropicが無効にした理由。それ以外は空
signing_secret内容whsec_ で始まる署名用シークレット

1組織に持てるエンドポイントは32個までで、無効なものも数に含まれます。

受信側で署名を検証して素早く返す

配信はStandard Webhooksの仕様に従い、webhook-id・webhook-timestamp・webhook-signature の3つのヘッダーが付きます。イベントを信用する前に、エンドポイントの署名シークレットで署名を検証します。検証にはStandard Webhooksに対応したライブラリならどれでも使えます。

返す側のルールは次の3点です。

  • 5秒以内に 2xx を返す。重い処理は返した後にやる
  • 同じイベントが重複して届くことがある。イベントの id(webhook-id ヘッダーと同じ値)で重複を弾く
  • 2xx 以外の応答や無応答は失敗として数えられる

次のコードは、Flaskでの受信側の骨組みです。署名検証にStandard Webhooksの standardwebhooks パッケージを使う例です。ストアはメモリ上の集合にしてありますが、実運用では永続ストアに置き換えます。

import os
from flask import Flask, request
from standardwebhooks import Webhook
import anthropic
 
app = Flask(__name__)
client = anthropic.Anthropic()
verifier = Webhook(os.environ["ORG_WEBHOOK_SECRET"])  # whsec_ で始まる値
seen_event_ids = set()  # 実運用ではDBやRedisに置く
 
 
@app.route("/anthropic-webhooks", methods=["POST"])
def receive():
    body = request.get_data(as_text=True)
    try:
        event = verifier.verify(body, dict(request.headers))
    except Exception:
        return "invalid signature", 400
 
    if event["id"] in seen_event_ids:
        return "", 200
    seen_event_ids.add(event["id"])
 
    profile_id = event["data"]["id"]
    enqueue_profile_check(profile_id)  # 取得と通知は返した後のワーカーで
    return "", 200
 
 
def enqueue_profile_check(profile_id: str) -> None:
    ...  # ジョブキューに積む
 
 
def check_profile(profile_id: str) -> None:
    try:
        profile = client.user_profiles.retrieve(profile_id)
    except anthropic.NotFoundError:
        return  # プロファイルは削除済み。自前の状態も閉じる
    status = profile.enforcement_status  # unrestricted / restricted / banned
    for action in profile.enforcement_actions:
        print(action.type, action.reason, action.expires_at)

署名はリクエスト本文の生のバイト列に対して計算されます。JSONにパースし直した文字列で検証すると一致しないので、本文は加工する前に検証へ渡します。Managed Agentsのwebhookで署名検証する実装手順でも同じ落とし穴を扱っています。

check_profile で使っている client.user_profiles.retrieve() は、ドキュメントに載っているPython SDKのメソッド名です。リクエストの anthropic-beta ヘッダーに user-profiles-2026-09-04 以前の値を付けていると、レスポンスから enforcement_status と enforcement_actions が抜けます。この2項目を読むリクエストでは、その値を外します。

取りこぼしを埋める

通知だけに頼ると、取りこぼしが起きる場面があります。ドキュメントが挙げているのは次の3つです。

場面何が起きるか
配信が有効になる前、または登録する前に措置が開いていた何が起きるかopened イベントが届かない。措置はプロファイルには残っている
配信が全回数失敗した何が起きるかAnthropicがそのイベントを破棄する
エンドポイントが無効になっていた何が起きるか無効の間のイベントは送られず、後から再送もされない

埋め方は共通で、プロファイルを措置の状態で絞り込んで一覧します。

curl -G "https://api.anthropic.com/v1/user_profiles" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  --data-urlencode "enforcement_status[]=restricted" \
  --data-urlencode "enforcement_status[]=banned"

この例は、一覧のクエリパラメーターを公式の説明に沿って組んだものです。ベータヘッダーを付ける場合は、前の節のとおり user-profiles-2026-09-04 以前の値を使いません。絞り込みフィルターは、その値が付いていると 400 を返します。

もう1つの注意があります。一覧のレスポンスは、limit より少ない件数や空の配列を返しても、まだ終わりとは限りません。next_page が null になるまでページを取り続けます。1ページ目が空だったことを「措置なし」と読むと、取りこぼしが見えなくなります。

運用としては、起動時と、エンドポイントを有効に戻した直後に、この一覧を一度回して自前の状態と突き合わせる形が素直です。通知はそのあとを追う役にして、定期的な突き合わせも残しておけば、破棄されたイベントの穴も埋まります。

自動で無効にされる条件と、元に戻す方法

Anthropicは、次のどれかに当てはまるエンドポイントを自動で無効にします。

  • リダイレクト(3xx)を返した
  • URLが公開IPアドレスではないものに解決された
  • 配信の失敗が続いた

無効の間のイベントは送られず、有効に戻した後にまとめて届くこともありません。無効になった理由は、エンドポイントの disabled_reason で確かめます。

戻すには、更新リクエストで "state": "enabled" を送ります。Anthropicが無効にした場合も同じです。

更新まわりでは、挙動の癖が2つあります。

落とし穴

enabled_eventsを空にしても購読は消えない

更新で enabled_events を渡すとリストは丸ごと置き換わります。ただし空のリストを送っても、エンドポイントは元のイベント種別を保ったままです。配信を止めたいときは "state": "disabled" を送るか、エンドポイントを削除します。

もう1つは署名シークレットの再発行です。POST /v1/organizations/webhooks/{webhook_endpoint_id}/regenerate_signing_secret を呼ぶと、古いシークレットはすぐに使えなくなります。以降の配信は、過去イベントの再試行も含めて新しいシークレットで署名されます。受信側のシークレットを差し替えるまでの間は検証が失敗し続けるので、再発行と差し替えは続けて行います。

404や400が返るとき

エンドポイントの登録や管理で出るエラーを、原因別に並べます。

ステータス原因
404原因anthropic-beta: webhooks-2026-10-07 ヘッダーを付けていない
404原因Anthropicが組織でorganization webhooksを有効にしていない
404原因組織でHIPAA readinessが有効になっている
404原因受け付けない種類の認証情報を使った
404原因webhook_endpoint_id が組織内のエンドポイントと一致しない
400原因URLの条件を満たさない、または作成時にイベント種別が空
400原因組織にデフォルトのワークスペースがない
400原因デフォルトワークスペースが顧客管理暗号鍵(CMEK)を使っている
400原因エンドポイントが32個を超える、または未対応のイベント種別を指定した
403原因ロールにそのリクエストの権限がない(エラーに必要な権限名が出る)
409原因有効な2つのエンドポイントが同じURLになる、または別のリクエストと同時に変更した

404 は理由が5つあり、メッセージだけでは切り分けにくい種類です。ヘッダーの付け忘れと認証情報の種類は自分で直せます。残りの3つ(有効化されていない・HIPAA・IDの不一致)は、先に組織の状態を確かめる必要があります。HIPAA関連の設定はClaude APIのZDRとは — HIPAAとのデータ保持の違いで整理されています。

409 のうち同時更新によるものは、リクエストをやり直せば通ります。CMEKの組織では、デフォルトワークスペースが暗号鍵を使っているだけで 400 になるため、CMEKの導入を検討している組織は先にこの制約を知っておく必要があります。

受け取る前に決めておくこと

配信が有効になる前に決めておくと、あとで迷わずに済む点です。

  • 通知を受けたあとの動き。サポート窓口への連絡、利用者向け画面の表示切り替え、自社側の課金や機能の停止など、措置の type と reason ごとに何をするか
  • 判定の基準。イベントの順序ではなく、取得したプロファイルの enforcement_status を正とする
  • 突き合わせの周期。起動時の一覧と定期実行で、破棄や無効化の穴を埋める
  • 署名シークレットの保管場所。返るのは作成時と再発行時の1回だけなので、受け取る手順を先に用意する

なお、Claude Platform on AWSではプロファイルの enforcement_status が常に unrestricted、enforcement_actions が常に空です。そこではAnthropicが措置を理由にリクエストを拒否しません。AWS経由で使っている場合は、どの面のプロファイルを監視するかを先に分けておきます。

この記事を共有:XはてブLinkedIn