Claude Media
Compliance API Activity Feedの使い方 — フィルタとカーソルページネーション

Compliance API Activity Feedの使い方 — フィルタとカーソルページネーション

Compliance APIのActivity Feedをフィルタとカーソルページネーションで取得する手順と、Activityオブジェクトの構造を一次資料から示します。

Activity Feedで何が取得できるか

Activity Feedは、組織内の認証・チャット・ファイル・プロジェクト・管理操作・プラットフォームのアクティビティを記録し、新しい順に返すエンドポイントです。発生から1分以内に照会できるようになり、6年間保持されます。記録は遡及しません。Compliance APIを組織で有効化した時点から記録が始まり、それ以前のアクティビティはバックフィルされません。

Compliance APIそのものの位置づけや、監査ログエクスポート・OpenTelemetry・Inference hooksとの違いはCompliance APIとはにまとめています。ここでは、Activity Feedを実際に呼び出すところから始めます。

Activity Feedが記録するイベントは幅広く、認証系(サインイン・サインアウト)、チャット・ファイル・プロジェクトの作成や更新、管理者による設定変更、SCIM経由のディレクトリ同期まで及びます。1つのエンドポイントを叩くだけで、これだけ多様なイベントを横断的に追えるのがActivity Feedの特徴です。

前提: 必要なスコープとキー

read:compliance_activitiesスコープを持つキーが必要です。Compliance Access Key(sk-ant-api01-...)とAdmin API key(sk-ant-admin01-...)のどちらでも、このスコープを持っていれば呼び出せます。キーをまだ作成していない場合は、Compliance APIのセットアップとアクセスキー作成を先に済ませてください。

どちらのキー種別を選ぶかは、Activity Feed以外のエンドポイントも使うかどうかで決まります。チャットやセッションのトランスクリプトまで取得する予定があるなら、最初からCompliance Access Keyで統一しておくと後からキーを作り直さずに済みます。逆に、監査ログの集計だけが目的でClaude Console組織の運用に閉じているなら、Admin API keyで十分です。

アクティビティを取得する

もっとも単純な呼び出しは、直近1件のActivityを取得するリクエストです。

curl --fail-with-body -sS \
  "https://api.anthropic.com/v1/compliance/activities?limit=1" \
  --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
  --header "anthropic-version: 2023-06-01"

レスポンスはdata(Activityの配列)、has_morefirst_idlast_idを持つJSONオブジェクトです。limitの既定値は100、最大は5,000まで指定できます。

activity_types・created_atでフィルタする

組織・アクター・アクティビティ種別・created_atの時間窓でフィルタできます。時間窓はcreated_at.gte / .gt / .lte / .ltのドット付きサブパラメータで指定します。activity_types[]actor_ids[]のような繰り返し可能なパラメータは、値の数だけ同じキーを配列ブラケット構文で渡します。

curl --fail-with-body -sS -G \
  "https://api.anthropic.com/v1/compliance/activities" \
  --data-urlencode "activity_types[]=claude_file_uploaded" \
  --data-urlencode "activity_types[]=claude_chat_created" \
  --data-urlencode "created_at.gte=2026-04-01T00:00:00Z" \
  --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
  --header "anthropic-version: 2023-06-01"

activity_types[]が受け付ける値はアクティビティの種類ごとに数百通りあります。全リストはAPIリファレンスで確認してください。actor_ids[]organization_ids[]も同じ配列ブラケット構文で複数指定できます。フィルタは組み合わせて渡せるので、特定ユーザーの特定期間のファイル操作だけを絞り込む、といった使い方もできます。

limitとレート制限の決め方

1リクエストあたりのlimitは既定100、最大5,000です。全エンドポイントは親組織単位で毎分600リクエストを共有するレート制限がかかっているため、limitを小さくして高頻度に叩くより、limitを大きめに固定してリクエスト回数自体を減らすほうがレート制限に当たりにくくなります。継続的な取り込みパイプラインを組む場合は、limit=5000のような上限に近い値を既定にしておき、has_moreでページ数を制御する設計が安定します。同じ親組織の下に複数のキーやリンク組織があるなら、この600req/分の枠は全体で共有されることも計画段階で織り込んでおきます。

カーソルでページ送りする

Activitiesは新しい順に返り、created_atが同じ場合はアクティビティIDで順序が決まります。ページングの方式はエンドポイントの種類によって異なります。

エンドポイント群ソート順方式パラメータ
Activitiesソート順新しい順方式カーソルパラメータafter_id / before_id(レスポンスはfirst_id / last_id)
チャット・チャットメッセージソート順古い順方式カーソルパラメータafter_id / before_id
組織・ユーザー・ロール・グループ等ソート順エンドポイント固有方式ページトークンパラメータpage(レスポンスはnext_page)
ローカル・リモートセッションソート順セッションは新しい順、メッセージは既定で古い順方式ページトークンパラメータpage(レスポンスはnext_page)

カーソルとページトークンは不透明な文字列として扱い、そのまま渡し戻します。内部フォーマットは安定しておらず、パースすると予告なく壊れます。Activitiesを新しい順にたどるときは、レスポンスのlast_idを次のリクエストのafter_idに渡すと古いページへ進みます。逆にfirst_idbefore_idに渡すと新しいページへ戻ります。has_morefalseになったら停止します。

過去分をさかのぼって取得するバックフィルは、has_morelast_idを軸にループを組みます。

cursor = stored_cursor
loop:
  if cursor is not null:
    page = GET /v1/compliance/activities?after_id={cursor}&limit=100
  else:
    page = GET /v1/compliance/activities?limit=100
  store(page.data)
  if page.last_id is not null:
    cursor = page.last_id
  if not page.has_more: break
persist(cursor)

最終last_idを永続化するのは、そこまでの全ページを保存し終えたあとにします。取りこぼしたページを後から特定できなくなるためです。途中で失敗したら、保存済みの位置から同じカーソルでやり直します。

Activityオブジェクトの構造

data配列の各要素は共通のトップレベル項目(id / created_at / organization_id / organization_uuid / actor / type)に加え、アクティビティ種別ごとの追加項目を持ちます。たとえばチャットイベントにはclaude_chat_idが、ファイルイベントにはfilenameが付きます。

organization_idは、サインインやサインアウト、Compliance API呼び出しのように特定の組織に紐づかないイベントではnullになります。actorは種別で持つ項目が変わる判別共用体です。統合の実装では、想定外のtypeactor.typeが来ても無視せず素通しし、フィールドが増えても壊れない作りにしておきます。

フィルタでactor_ids[]に渡す値は、actor.typeによって意味が変わります。user_actorならメールアドレスの変更に影響されないuser_idが安定した識別子です。api_actorならapi_key_idadmin_api_key_actorならadmin_api_key_idを使います。どの識別子を主キーにするかを先に決めておくと、フィルタ条件を組むときに迷いません。

認証イベントも同じフィードに乗る

Activity Feedは、アプリ内の操作だけでなくサインイン・サインアウトの認証イベントや、Compliance API自体への呼び出し(compliance_api_accessed)も同じフィードに記録します。誰がいつCompliance APIを叩いたかという、コンプライアンスチーム自身の操作履歴も後から追跡できるということです。認証系のイベントはorganization_idを持たない点が、チャットやファイルのイベントと異なります。取得したイベントを組織別に集計する処理を書くときは、organization_idnullになりうることを前提に分岐を入れておきます。1つの取得処理で全種類を一律に扱おうとすると、この分岐漏れで組織別の集計が静かに崩れます。

claude_chat_viewedのようなclaude_*_viewed系のアクティビティは、人がその内容を見たことではなく、Claudeアプリがサーバーからチャット・ファイル・プロジェクトを読み込んだことを示します。読み込みは重複排除されず、Web・デスクトップ・モバイルの各アプリが別々のタイミングで、時にはバックグラウンドで読み込みます。件数をそのまま「何回開かれたか」と解釈しないようにします。

よくあるつまずき

  • has_moreを確認せず1ページで満足する: レート制限に近づくと1ページに収まらないことが増えます。ループの終了条件は必ずhas_morefalseになったかで判定します
  • カーソルをパースしようとする: 内部フォーマットは仕様に含まれず、変更されても通知されません。文字列としてそのまま保存・送信します
  • ローカルセッションのページトークンを24時間放置する: セッションメッセージのウォークは、最初のページから24時間でpageトークンが失効します。取得を分割する場合は24時間以内に完了・再開するか、pageパラメータなしで再開始します
  • セッション系エンドポイントでhas_moreを探す: ローカル・リモートセッションのエンドポイントだけはhas_moreを返さず、next_pagenullになったら停止するという別の停止条件を使います
  • activity_types[]を1つのカンマ区切り文字列で渡す: 配列ブラケット構文が必要で、値ごとにactivity_types[]=...を繰り返します。カンマ区切りは1つの値として扱われ、フィルタが効きません
  • claude_*_viewedの件数を利用実態の指標に使う: アプリの読み込み挙動に左右され、重複排除もされないため、プラットフォームをまたいだ比較には向きません。件数の増減だけを見て利用が増えたと判断しないようにします
  • 1件だけ多く取得できたことを異常とみなす: at-least-onceの配信契約では、リトライ後の再取得で同じアクティビティが重複することがあります。idで重複排除する前提で件数を評価します。集計より先に重複排除の処理を挟みます

まとめ

Activity Feedは、時間窓か種別でフィルタし、after_id / before_idのカーソルでページ送りする、というシンプルな設計です。ローカルセッションのページトークンだけは24時間で失効する点と、has_moreの有無がエンドポイント群で異なる点が実装時に見落としやすいポイントです。

単発の照会ならここまでの内容で十分ですが、SIEMへ継続的に流し込むパイプラインを組むなら、ポーリングとカーソル駆動のどちらの消費パターンを選ぶか、保持期間をどう設計するかという別の意思決定が必要になります。継続運用に切り替える段階で必要になる設計はCompliance APIをSIEMと連携するで扱います。

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