user-profiles changedmanage-claude/user-profiles
Nearest release: v2.1.306, published under an hour before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
## Decide who gets a profile ## What a profile contains and how Anthropic uses it ## Before you begin ## Create a profile for each end customer ### What to tell Anthropic about an end customer ## Attribute each request ### Attribute requests on Amazon Bedrock and Google Cloud ### Identify individual users within a company ## Keep profiles current ### Update a profile ### Delete a profile ## Next steps
The whole hunk
652 lines, new pageA whole new page. There's nothing to diff it against, so here is what it says.
---
title: User profiles for end-customer attribution
url: https://platform.claude.com/docs/en/manage-claude/user-profiles
description: Attribute API requests to the end customers your platform serves, so a safety enforcement action can apply to one profile instead of your whole organization.
---
User profiles ("profiles") tell Anthropic which of your end customers each API request is for. A safety enforcement action, such as a hold or a block, can then apply to one end customer instead of your whole organization. When it does, the rest of your traffic is unaffected.
If you operate a platform or gateway, or resell API access, the requests you send for your end customers arrive under your organization. Anthropic runs automated safety classifiers over API traffic. Without a profile on the request, one end customer can trigger an enforcement action that applies to your whole organization.
You register each end customer once with `POST /v1/user_profiles` and store the `uprof_` ID it returns. Then you send that ID in the `anthropic-user-profile-id` header on every request you make on that end customer's behalf.
Profiles aren't billable and don't affect pricing.
## Decide who gets a profile
What a profile stands for depends on how you sell Claude: a person who uses your product, or a company you resell API access to. These two cases cover most platforms. The profile's `access_type` field says which one applies.
| Who the traffic is for | Profile | `access_type` |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| A signed-up user of your product | One for each user, created when they sign up. | `application` (the default, set when you leave `access_type` out) |
| A company you resell API access to, for example as a gateway | One for each company, not for each person within it. | `passthrough` (not the default, so you have to send it) |
| Your own organization | None. Anthropic counts a request with no profile ID as your own usage. Keep that usage in a [separate organization](https://platform.claude.com/docs/en/manage-claude/user-profiles#before-you-begin). | Not applicable |
| A workspace in your organization | No separate profile. A profile belongs to your organization, and its ID works on requests through any workspace in it. | Not applicable |
## What a profile contains and how Anthropic uses it
A profile contains only what you send about the end customer, plus any [program status](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal#after-the-end-customer-links-the-profile) that Anthropic sets. It doesn't contain conversation content. Anthropic uses the details you send to attribute requests, to monitor for abuse, for enforcement of the [Usage Policy](https://www.anthropic.com/legal/aup), and to enable application and access to trusted access programs. Anthropic doesn't verify the details.
Anthropic processes profiles in accordance with the [Privacy Policy](https://www.anthropic.com/legal/privacy).
## Before you begin
You create and manage profiles in one of the following:
* An organization on the Claude API.
* An organization on [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws). The calling principal needs the [user profile IAM actions](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions#user-profiles).
* A [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) deployment [hosted on Anthropic](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#hosting-options), not one hosted on Azure. You don't need an organization on the Claude API or Claude Platform on AWS. Use your Foundry endpoint, with the same base URL and authentication that you use for inference.
Amazon Bedrock and Google Cloud don't have the `/v1/user_profiles` endpoints. If your inference runs there, create your profiles in an organization on the Claude API or Claude Platform on AWS. On Amazon Bedrock, profiles work only with [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock). See [Attribute requests on Amazon Bedrock and Google Cloud](https://platform.claude.com/docs/en/manage-claude/user-profiles#attribute-requests-on-amazon-bedrock-and-google-cloud).
Keep the traffic you send for your end customers in one organization and your own internal usage in another. Profiles belong to an organization, not a workspace, so separate workspaces in one organization aren't enough. Only the organization for end-customer traffic needs user profiles. To create another organization on the Claude API, see the "How to create a new organization" section of [Creating and managing Workspaces in the Claude Console](https://support.claude.com/en/articles/9796807) in the Claude Help Center.
The examples call the Claude API with an API key. You don't need an [Admin API key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys). On Claude Platform on AWS, use its base URL and authentication.
## Create a profile for each end customer
Create one profile for each end customer whose traffic you send to Claude. Create it once, in your customer-onboarding flow. `POST /v1/user_profiles` isn't idempotent, so every call creates a new profile, even when `reference_id` matches an existing one. If you already have end customers without profiles, see the guidance on registering an existing customer base later in this section.
The following example registers a company that buys API access through a gateway, so it sets `access_type` to `passthrough`. For an `application` profile, leave out `access_type`, and describe one end user in `name` and `external_user_details` instead of a company. [Decide who gets a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles#decide-who-gets-a-profile) compares the two access types.
<CodeGroup>
```bash cURL
curl https://api.anthropic.com/v1/user_profiles \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"name": "Acme Analytics, Inc.",
"access_type": "passthrough",
"external_user_details": {
"reference_id": "cust-8f2a1c",
"country": "US"
}
}'
```
```bash CLI
ant user-profiles create \
--name "Acme Analytics, Inc." \
--access-type passthrough \
--external-user-details '{reference_id: cust-8f2a1c, country: US}'
```
```python Python
client = anthropic.Anthropic()
profile = client.user_profiles.create(
name="Acme Analytics, Inc.",
access_type="passthrough",
external_user_details={"reference_id": "cust-8f2a1c", "country": "US"},
)
print(profile.id)
```
```typescript TypeScript
const client = new Anthropic();
const profile = await client.userProfiles.create({
name: "Acme Analytics, Inc.",
access_type: "passthrough",
external_user_details: { reference_id: "cust-8f2a1c", country: "US" }
});
console.log(profile.id);
```
```csharp C#
AnthropicClient client = new();
var profile = await client.UserProfiles.Create(new()
{
Name = "Acme Analytics, Inc.",
AccessType = UserProfileAccessType.Passthrough,
ExternalUserDetails = new()
{
ReferenceID = "cust-8f2a1c",
Country = "US"
}
});
Console.WriteLine(profile.ID);
```
```go Go
client := anthropic.NewClient()
profile, err := client.UserProfiles.New(context.Background(), anthropic.UserProfileNewParams{
Name: anthropic.String("Acme Analytics, Inc."),
AccessType: anthropic.UserProfileAccessTypePassthrough,
ExternalUserDetails: anthropic.UserProfileExternalUserDetailsParams{
ReferenceID: anthropic.String("cust-8f2a1c"),
Country: anthropic.String("US"),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(profile.ID)
```
```java Java
import com.anthropic.models.userprofiles.UserProfileAccessType;
import com.anthropic.models.userprofiles.UserProfileCreateParams;
import com.anthropic.models.userprofiles.UserProfileExternalUserDetailsParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = UserProfileCreateParams.builder()
.name("Acme Analytics, Inc.")
.accessType(UserProfileAccessType.PASSTHROUGH)
.externalUserDetails(UserProfileExternalUserDetailsParams.builder()
.referenceId("cust-8f2a1c")
.country("US")
.build())
.build();
var profile = client.userProfiles().create(params);
IO.println(profile.id());
}
```
```php PHP
$client = new Client();
$profile = $client->userProfiles->create(
name: 'Acme Analytics, Inc.',
accessType: 'passthrough',
externalUserDetails: ['referenceID' => 'cust-8f2a1c', 'country' => 'US'],
);
echo $profile->id, PHP_EOL;
```
```ruby Ruby
client = Anthropic::Client.new
profile = client.user_profiles.create(
name: "Acme Analytics, Inc.",
access_type: :passthrough,
external_user_details: { reference_id: "cust-8f2a1c", country: "US" }
)
puts profile.id
```
</CodeGroup>
The response is the new profile:
```json
{
"type": "user_profile",
"id": "uprof_011CZkZCu8hGbp5mYRQgUmz9",
"name": "Acme Analytics, Inc.",
"access_type": "passthrough",
"external_user_details": {
"reference_id": "cust-8f2a1c",
"onboarded_at": null,
"account_status": null,
"entity_type": null,
"country": "US",
"name_hash": null,
"email_hash": null
},
"metadata": {},
"programs": {
"cyber": null,
"efs": null
},
"created_at": "2026-03-15T10:00:00Z",
"updated_at": "2026-03-15T10:00:00Z"
}
```
Store the `id` on your customer record, and have your service instances read it from there instead of creating their own profile. You retrieve, update, and delete a profile by that `id`. The `programs` field is read-only, and attribution doesn't use it. It holds the end customer's status in each program that Anthropic runs. For what its values mean, see [which programs apply to a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal#after-the-end-customer-links-the-profile).
There's no cap on the number of profiles in an organization, but profile creation is rate limited. Before you register an existing customer base in bulk, contact your Anthropic account team.
### What to tell Anthropic about an end customer
Every field is optional. You can send `name`, `metadata`, and these fields in `external_user_details`: `entity_type`, `country`, `reference_id`, `onboarded_at`, `account_status`, `name_hash`, and `email_hash`. The [Create a profile](https://platform.claude.com/docs/en/api/user_profiles/create) reference describes each field, with its type, format, and length limit.
Follow these rules when you set the fields:
* **Unknown values:** If you don't know a value, leave it out instead of sending a placeholder. You can replace a value in `external_user_details` later, but you can't clear it.
* **Company names:** For a `passthrough` profile, send the company's legal name in `name` if you know it.
* **Country:** In `country`, send the end customer's country, not yours.
* **Your own ID:** In `reference_id`, send your own stable identifier for the end customer. It doesn't have to be unique.
* **Names and email addresses you can't share:** Leave out `name` and send `external_user_details.name_hash` instead. For the email address, send `external_user_details.email_hash`. A profile has no field for the address itself.
* **Hashes:** Compute the hashes yourself, with a function you choose. They show Anthropic which of your profiles share a name or an email address. Use the same function and the same case and whitespace normalization for every profile, because only values computed the same way match.
## Attribute each request
Send the profile ID in the `anthropic-user-profile-id` header on every request you make on the end customer's behalf. The SDKs and the CLI have an argument that sends the header for you: `user_profile_id` (java: `userProfileId`; php: `userProfileID`; csharp, go: `UserProfileID`; cli: `--user-profile-id`).
<CodeGroup>
```bash cURL
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-user-profile-id: uprof_011CZkZCu8hGbp5mYRQgUmz9" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Hello, Claude"}
]
}'
```
```bash CLI
ant messages create \
--model claude-opus-5-5 \
--max-tokens 1024 \
--message '{role: user, content: "Hello, Claude"}' \
--user-profile-id uprof_011CZkZCu8hGbp5mYRQgUmz9
```
```python Python
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
user_profile_id="uprof_011CZkZCu8hGbp5mYRQgUmz9",
)
print(message)
```
```typescript TypeScript
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello, Claude" }],
user_profile_id: "uprof_011CZkZCu8hGbp5mYRQgUmz9"
});
console.log(message);
```
```csharp C#
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus5_5,
MaxTokens = 1024,
Messages = [new() { Role = Role.User, Content = "Hello, Claude" }],
UserProfileID = "uprof_011CZkZCu8hGbp5mYRQgUmz9"
};
var message = await client.Messages.Create(parameters);
Console.WriteLine(message);
```
```go Go
client := anthropic.NewClient()
message, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5_5,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
Cut at 300 lines. The page has the rest.
No line in this hunk matches that.