News

Claude API User Profiles: Isolate Bans per End Customer, Not per Organization

On October 20, 2026, Anthropic launched user profiles, a way to tell the Claude API which of your end customers each request is for. On October 21 it added the enforcement_status and enforcement_actions fields that show whether Anthropic has restricted or banned one of them. If you run a multi-tenant product, a gateway or a reseller setup, this is the change that decides how far one abusive customer can reach. Anthropic’s own guide puts the risk plainly: without a profile on the request, one end customer can trigger an enforcement action that applies to your whole organization. With one, the action can apply to that customer and leave the rest of your traffic alone.

October 26, 2026

Rows of cyan-lit rails run down a dark corridor toward an orange-lit doorway, with one small black box glowing orange on a rail near the center.
A profile ID gives Anthropic one lane to stop, so a single tenant’s enforcement action leaves the rest of your traffic moving.

One Profile per Customer, Created Once

The model is small. You register each end customer once with POST /v1/user_profiles, store the uprof_ ID it returns on your own customer record, and send that ID in the anthropic-user-profile-id header on every request you make for that customer. Profiles are not billable and do not change pricing. Anthropic does not describe them as mandatory; what it describes is the cost of leaving them out.

Three details from the documentation decide how you wire it up:

Creation is rate limited, and there is no cap on the number of profiles. If you are backfilling an existing customer base, Anthropic asks you to contact your account team before registering it in bulk. Tenant isolation inside your own database is a separate layer with its own failure modes; the PostgreSQL row-level security guide covers that side.

Which Header, and Which Beta Value

The question most teams get wrong is the beta header, because user profiles went through several beta versions before launch. The current reference lists user-profiles-2026-03-24, user-profiles-2026-08-18 and user-profiles-2026-09-04. As of October 26, 2026, the guide’s instruction is to send no user-profiles- value in anthropic-beta: under user-profiles-2026-09-04 and earlier, responses leave out both enforcement fields, and the enforcement_status[] list filter is rejected with an invalid_request_error. If an older integration pinned one of those values, removing it is the migration.

The header itself works on Messages, token counting and Message Batches requests. The SDKs expose it as an argument, user_profile_id in Python and TypeScript:

import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": prompt}],
    user_profile_id=customer.anthropic_profile_id,
)

The Claude API checks the ID on every request and returns a 400 invalid_request_error when it is malformed or belongs to another organization, so a wrong ID fails loudly. Batches are the exception that bites. The header applies to every request in the batch, so a batch can carry only one customer’s traffic. Creating a batch checks only the ID’s format: a well-formed ID from the wrong organization still creates the batch, and each request then comes back as an errored result. Group batch jobs by tenant and inspect per-request results, not just the batch status. For the API version and SDK majors that ship the argument, see the 2026-10-21 migration guide.

Finding Restricted and Banned Profiles, All of Them

Every response that returns a profile carries enforcement_status. To find the profiles that need attention, list them with the filter. The pitfall is pagination: with a filter set, the service examines a bounded number of profiles per request, so a page may hold fewer than limit profiles, or none, and still carry a next_page. The reference is explicit that only a null next_page means the listing is complete. An empty page is not the end.

import os
import httpx

STATUSES = ["restricted", "banned", "pending"]

def enforced_profiles():
    headers = {
        "x-api-key": os.environ["ANTHROPIC_API_KEY"],
        "anthropic-version": "2026-10-21",
    }
    page = None
    while True:
        params = [("enforcement_status[]", s) for s in STATUSES] + [("limit", "100")]
        if page is not None:
            params.append(("page", page))
        resp = httpx.get("https://api.anthropic.com/v1/user_profiles",
                         params=params, headers=headers, timeout=30)
        resp.raise_for_status()
        body = resp.json()
        yield from body["data"]
        page = body["next_page"]
        if page is None:
            return

The guide’s example filters on restricted and banned. The reference defines a fourth value, pending, for a profile whose restriction can be cleared by an identity check that the end customer has submitted and Anthropic is still reviewing. That profile still has an open action, so the loop above includes it. Two more documented behaviours belong in the error handling: the filter can fail with overloaded_error when enforcement data cannot be read for the moment, so retry rather than treating the run as clean, and Anthropic may add values, so treat an unrecognised status as restricted.

Map Each Status to Product Behaviour

StatusWhat the docs sayA reasonable product response
unrestrictedNo action is open.Serve normally.
restrictedAt least one action is open, none is a ban. Anthropic refuses some or all requests carrying the ID. If an action’s action is verify, the end user can clear it now with an identity check.Degrade that tenant’s AI features and say why; surface the verification path when verify is set.
pendingThe end user has submitted the identity check and review has not ended.Show “under review”; do not loop retries against refused requests.
bannedAnthropic has stopped serving the end user where the ban applies and does not plan to serve them there again. The end user cannot clear it.Stop sending that customer’s traffic and record your own decision in account_status.

The product response column is our recommendation, not Anthropic’s. The one rule that follows directly from the docs is the negative one: do not route a restricted customer’s traffic without the header. A request with no profile ID counts as your own usage, which puts the whole organization back in the blast radius you just removed.

Webhooks require access; keep polling for reconciliation

Anthropic added organization webhooks to the Admin API on October 20, in beta behind webhooks-2026-10-07, with two events: user_profile.enforcement_action_opened and user_profile.enforcement_action_resolved. Access is by request through your Anthropic account team, and the feature is unavailable to organizations with HIPAA readiness. If event delivery has not been enabled for your organization, use the polling loop above to detect open actions. Keep polling as reconciliation after enabling webhooks: Anthropic drops an event when every retry fails, and sends no opened event for actions opened before event delivery was enabled for your organization or before you registered your endpoint.

What Not to Put in a Profile

A profile holds only what you send about the customer, plus the program and enforcement status that Anthropic sets. It never contains conversation content, but that does not make it a safe place for personal data. Anthropic’s data retention page marks the user profiles API as not eligible for zero data retention and not HIPAA-eligible. Profile data is retained under the standard policy until you delete the profile. HIPAA-enabled organizations can use profiles, but PHI must not be included in the profile data you send.

In practice that means three rules. Use reference_id for your own opaque customer key, not an email address. If you cannot share a name or email, send name_hash and email_hash computed with one function and one normalization across all profiles, because only identically computed hashes match. And keep metadata, which allows at most 16 keys of up to 64 characters with values up to 512 characters, for operational tags such as plan or region. Deleting a profile removes what you supplied but not the trust and safety records Anthropic keeps about that ID, and inference requests carrying the deleted ID can still succeed for about 10 minutes.

The operating decision

Create one profile per end customer at onboarding: an individual product user for application, or a company buying API access for passthrough. Store the ID and refuse to send that customer’s traffic without it. Remove any user-profiles- beta value, batch by profile ID, and run the filtered listing on a schedule until next_page is null. Minimize the data you put in profiles: use opaque IDs and hashes where possible, and include no PHI. The broader integration patterns live in the Claude API guide.

Sources checked October 26, 2026