Claude APIのUser Profilesでエンドユーザーを識別する手順
User Profiles APIでプロファイルを作り、anthropic-user-profile-idヘッダーでリクエストを紐づける流れと、applicationとpassthroughの違い、ベータヘッダー3世代の移行点。
Claude APIのUser Profilesでエンドユーザーを識別する手順
User Profiles APIは、自社サービスの利用者や再販先の企業を「プロファイル」としてAnthropic側に登録し、APIリクエストをそのプロファイルに紐づけるためのベータAPIです。紐づけは anthropic-user-profile-id ヘッダーに、uprof_ で始まるプロファイルIDを載せるだけで済みます。
公式には概念解説のページが無く、APIリファレンスだけで仕様が書かれています。この記事では、その内容を作成から運用までの順に並べ直します。
User Profilesは何を記録する仕組みか
プロファイルは、プラットフォーム(Claude APIを組み込んだ自社サービス)がAPI経由で扱う相手の記録です。相手は、自社製品のエンドユーザーの場合もあれば、Claudeへのアクセスを再販している企業の場合もあります。
Messages、Message Batches、トークン数カウントの各リクエストは、プロファイルの id を anthropic-user-profile-id ヘッダーで送ると、その相手に帰属するものとして扱われます。Messagesのリファレンスでは、このヘッダーは「自組織以外の当事者のために動くときに使う」と説明されています。
ヘッダーを使うには user-profiles 系のベータヘッダーも必要です。ベータヘッダーの書式や併用ルールはClaude APIでanthropic-betaヘッダーを使う方法にまとめています。
なお、組織のメンバーやAPIキーを管理するAdmin系のAPIは別物です。そちらはClaude User Management APIでメンバー管理を実装するで扱っています。
使えるエンドポイントは5つ
プロファイルの操作は次の5つで完結します。
| 操作 | メソッドとパス |
|---|---|
| 作成 | メソッドとパスPOST /v1/user_profiles |
| 一覧 | メソッドとパスGET /v1/user_profiles |
| 取得 | メソッドとパスGET /v1/user_profiles/{user_profile_id} |
| 更新 | メソッドとパスPOST /v1/user_profiles/{user_profile_id} |
| 登録URLの発行 | メソッドとパスPOST /v1/user_profiles/{user_profile_id}/enrollment_url |
削除のエンドポイントはリファレンスに載っていません。更新がPATCHやPUTでなくPOSTである点も、他のREST APIの感覚で書くと外しやすいところです。
リクエストには共通で anthropic-version と X-Api-Key が要ります。加えて、資格情報が複数のワークスペースで動かせる場合だけ、anthropic-workspace-id ヘッダーでワークスペースを選びます。特定のワークスペースに属する資格情報なら省略でき、送るなら一致していなければなりません。
ベータヘッダーは3世代ある
プロファイルの項目名は、ベータヘッダーの世代で変わります。リファレンスに載っている user-profiles 系は次の3つです。
| ベータヘッダー | ユーザー識別子 | 開設日時 | 追加された項目 |
|---|---|---|---|
user-profiles-2026-03-24 | ユーザー識別子external_id | 開設日時なし | 追加された項目なし |
user-profiles-2026-08-18 | ユーザー識別子external_id | 開設日時external_user_onboarded_at | 追加された項目access_type |
user-profiles-2026-09-04 | ユーザー識別子external_user_details.reference_id | 開設日時external_user_details.onboarded_at | 追加された項目external_user_details のオブジェクト一式 |
access_type は「08-18以降のベータヘッダーで返る」と書かれています。09-04では、external_id と external_user_onboarded_at の代わりに、同じ値を external_user_details の中へ入れて送ります。
external_user_details は09-04のヘッダーでだけ受け付けられ、レスポンスにもそのヘッダーのときだけ現れます。古いヘッダーのまま呼ぶと、reference_idは従来どおり最上位の external_id として返ります。
移行の要点は1つです。既存コードが external_id に自社のユーザー IDを入れているなら、09-04へ上げる時点で external_user_details.reference_id に置き換えます。
プロファイルを作る
最小の作成リクエストは、公式の例では次の形です。ベータヘッダーは08-18で、自社側のユーザー IDと開設日時を送っています。
curl https://api.anthropic.com/v1/user_profiles \
-H 'Content-Type: application/json' \
-H 'anthropic-version: 2023-06-01' \
-H 'anthropic-beta: user-profiles-2026-08-18' \
-H "X-Api-Key: $ANTHROPIC_API_KEY" \
-d '{
"external_id": "user_12345",
"external_user_onboarded_at": "2024-11-02T08:15:00Z",
"metadata": {}
}'レスポンスには id(uprof_011CZkZCu8hGbp5mYRQgUmz9 のような形)、created_at、updated_at、metadata、trust_grants、type(常に user_profile)が含まれます。以降のリクエストでは、この id を保存して使います。
09-04のヘッダーで同じことをするなら、識別子と開設日時を external_user_details にまとめます。次はリファレンスのパラメーター定義から組み立てた例で、公式のサンプルそのものではありません。
curl https://api.anthropic.com/v1/user_profiles \
-H 'Content-Type: application/json' \
-H 'anthropic-version: 2023-06-01' \
-H 'anthropic-beta: user-profiles-2026-09-04' \
-H "X-Api-Key: $ANTHROPIC_API_KEY" \
-d '{
"name": "Example User",
"external_user_details": {
"reference_id": "user_12345",
"onboarded_at": "2024-11-02T08:15:00Z",
"entity_type": "individual",
"country": "JP",
"account_status": "active"
},
"metadata": {"plan": "free"}
}'作成時に必須のフィールドはありません。access_type、external_id、external_user_details、metadata、name はすべて任意です。
metadata は自由形式のキーと値で、最大16キー、キーは64文字まで、値は512文字までです。値は空でない文字列でなければなりません。name と external_id は1〜255文字です。external_id は一意である必要がなく、同じ値で複数のプロファイルを作っても弾かれません。
リクエストにヘッダーを付ける
プロファイルができたら、Messages APIに anthropic-user-profile-id を足します。次はMessages APIの呼び出しにヘッダーを付ける例です。
curl https://api.anthropic.com/v1/messages \
-H 'Content-Type: application/json' \
-H 'anthropic-version: 2023-06-01' \
-H 'anthropic-beta: user-profiles-2026-09-04' \
-H 'anthropic-user-profile-id: uprof_011CZkZCu8hGbp5mYRQgUmz9' \
-H "X-Api-Key: $ANTHROPIC_API_KEY" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello"}]
}'ヘッダーを受け付けると公式に書かれているのは、次の3つです。
- Messagesの作成(
/v1/messages) - Message Batchesの作成
- トークン数カウント(count_tokens)
バッチには挙動の注意が1つあります。バッチに付けたヘッダーは、バッチ内の全リクエストに適用されます。個別リクエストの本文に user_profile_id があって、ヘッダーと食い違うと、そのリクエストはエラーになります。ユーザーごとに帰属先を変えたいなら、ユーザー単位でバッチを分けるか、ヘッダーと本文の値を必ず同じにします。
applicationとpassthroughの使い分け
access_type は、その相手をプラットフォームがどう扱うかを表します。値は2つで、省略すると application になります。
| 値 | プロファイルが表すもの | 典型的な場面 |
|---|---|---|
application(既定) | プロファイルが表すもの自社製品がAPI上に築いた製品の、個々のエンドユーザー | 典型的な場面チャットサービスの会員1人につき1プロファイル |
passthrough | プロファイルが表すものClaudeへのアクセスを再販している会社 | 典型的な場面法人顧客を1社1プロファイルで持つ |
passthrough のとき、name には再販先の会社名を入れます(分かっている範囲で)。開設日時の意味も変わり、application ではエンドユーザーの登録時期、passthrough では、その会社がプラットフォームの顧客になった時期を指します。
access_type は更新でも変えられます。省略すれば現状維持です。
external_user_detailsに何を入れるか
09-04で追加された external_user_details は、プラットフォーム自身が把握している相手の情報を申告するためのオブジェクトです。すべて任意で、Anthropicは内容を検証しません。レスポンスでは全フィールドが必ず存在し、申告されるまで null になります。
| フィールド | 内容 |
|---|---|
reference_id | 内容自社側の識別子。自社DBの行のキーなど。1〜255文字 |
entity_type | 内容individual / business / non_profit / government |
account_status | 内容active / suspended / blocked |
country | 内容相手の国(プラットフォームの国ではない)。大文字2文字のISO 3166-1 alpha-2 |
email_hash | 内容自社で計算したメールアドレスのハッシュ |
name_hash | 内容自社で計算した名前のハッシュ |
onboarded_at | 内容開設日時(RFC 3339)。現在から1分を超える未来は不可 |
ハッシュ2種は、Anthropicが「意味を持たない文字列」として扱い、ハッシュ関数も指定していません。生のメールアドレスや氏名を送らずに、同一人物かどうかを追える形で持たせる設計と読めます。
country は形式だけが検査され、大文字2文字のASCIIであれば通ります。存在しない国コードでもエラーにならない可能性があるため、値の正しさは自社側で保証する前提です。
account_status の使い道は、停止・遮断した利用者の扱いをAnthropicに伝えることです。suspended は「制限したが復旧しうる」、blocked は「締め出した」という意味だと定義されています。
更新のルール:消せない値がある
更新はPOSTで、送ったフィールドだけが変わります。挙動はフィールドごとに違うので、表にまとめます。
| 対象 | 更新時の挙動 |
|---|---|
name、access_type、external_id | 更新時の挙動送ると置き換わる。省略すれば変わらない |
external_user_details の各項目 | 更新時の挙動送った項目だけ置き換わる。一度入れた値は消せず、null は拒否される |
external_user_onboarded_at | 更新時の挙動同様に、一度入れると消せず null は拒否される |
metadata | 更新時の挙動既存にマージされる。同じキーは上書きされ、キーを消すには値を空文字にする |
metadata では、値を空文字にするとキーが消えます。ところが作成時は「値は空でない文字列」とされているため、作成と更新で空文字の意味が違います。作成時のペイロードを更新にそのまま流用すると挙動がずれます。
trust_grantsとenrollment URL
プロファイルのレスポンスには trust_grants があります。付与名をキーにしたマップで、値は status を持ちます。公式の例では "cyber": {"status": "active"} の形です。
status は active、pending、rejected の3つです。有効な付与も申請中の付与も無いときは、そのキー自体が現れません。付与の状態が変わると、プロファイルの updated_at も更新されます。
この付与を得るための入口が、登録URL(enrollment URL)です。次のように発行します。
curl -X POST \
https://api.anthropic.com/v1/user_profiles/$USER_PROFILE_ID/enrollment_url \
-H 'anthropic-version: 2023-06-01' \
-H 'anthropic-beta: user-profiles-2026-08-18' \
-H "X-Api-Key: $ANTHROPIC_API_KEY"レスポンスは type: "enrollment_url"、url、expires_at です。URLは、プロファイルが表す相手に渡すためのもので、expires_at まで有効です。公式の例では、有効期限は発行の15分後になっています。
公式の説明では、相手が信頼付与(trust grant)に登録するためのURLです。どんな付与名があるか、審査に何が要るか、付与されると何が変わるかは、User Profilesのリファレンスには書かれていません。Messagesのリファレンスには、サイバーやバイオ分野の研究向けに信頼済みアクセスプログラム経由で提供されるモデルの記述があり、付与名の cyber との関係を想像したくなります。ただし両者を結びつける説明は公式に見当たらないため、この記事では関係を断定しません。
一覧と取得でプロファイルを引く
GET /v1/user_profiles には、次のクエリパラメーターがあります。
| パラメーター | 内容 |
|---|---|
limit | 内容1〜100。既定20 |
order | 内容asc / desc。既定 desc |
order_by | 内容created_at(既定)/ name |
page | 内容前回レスポンスの next_page の値。省略で最初のページ |
name での並べ替えはASCII文字の大文字小文字を区別せず、名前の無いプロファイルは昇順でも降順でも最後に来ます。レスポンスは data の配列と、次のページがあるときの next_page です。
自社のIDからプロファイルを探すエンドポイントは、リファレンスにはありません。external_id は一意でもないため、自社ユーザー IDから uprof_ IDを引く対応表は、自社のDBで持っておく形になります。
つまずきやすい点
- 09-04では識別子の送り先が
external_user_details.reference_idに変わる。external_idのまま上げない - バッチで、ヘッダーと本文の
user_profile_idを食い違わせない metadataの空文字は、作成では不可で、更新ではキー削除を意味するexternal_user_detailsの値は、一度入れると消せない。検証用の仮値を本番のプロファイルに入れないcountryは自国ではなく、相手の国を入れる
ヘッダーが3世代あるため、SDKでも生のHTTPでも、どの世代を送っているかがコードから見えることが大切です。ベータ名を1か所の定数にまとめる方針は、anthropic-betaヘッダーの記事で触れています。バージョンヘッダー側の考え方はanthropic-versionヘッダーとClaude APIのバージョン管理方針を参照してください。
導入前に決めておくこと
User Profilesは、ヘッダー 1本で帰属先を渡せる分、何を1プロファイルに割り当てるかを最初に決める必要があります。決めるのは次の3点です。
- 相手の単位。エンドユーザー 1人ごとの
applicationにするか、法人ごとのpassthroughにするか - 自社IDとの対応表を、どこに持つか
- 個人を特定する値を、平文でなくハッシュで送るか
ハッシュ関数は公式が指定していないので、自社で決めて固定します。あとから関数を変えると、同じ人物でもハッシュが変わります。
ベータAPIなので、ヘッダー名が今後も変わる可能性があります。09-04で識別子の置き場所が変わった前例が、すでにその一例です。