Claude User Profiles: Per-Client Enforcement Only on Platforms Verifying IDs Per Request

Anthropic's user profiles shift enforcement from organization to end-client level, but only on platforms that verify profile IDs per request; gateways must create profiles at registration, store IDs on customer records, inject headers at the sole egress point, and handle platform-specific gaps like Bedrock's format-only validation and AWS's missing enforcement reporting.

Architecture Development Notes
Architecture Development Notes
Architecture Development Notes
Claude User Profiles: Per-Client Enforcement Only on Platforms Verifying IDs Per Request

Organization, Workspace, and Profile Are Three Distinct Layers

A profile is an Anthropic-side record containing only the fields you submit about an end client plus Anthropic-written project and enforcement status — no conversation content. Its documented purposes: attribution, abuse monitoring, Usage Policy enforcement, and trusted project access applications. Critically, Anthropic does not verify the details you submit; those fields enter the judgment pipeline unchecked, so the cost of errors falls on you.

Layer Definitions and Enforcement Scope

Organization — Profile owner; a profile is created in exactly one organization. Can narrow enforcement scope: yes — documented approach is to put end-client traffic in a separate organization.

Workspace — Resource grouping inside an organization. Can narrow enforcement scope: no — profile belongs to the organization; same ID works across all workspaces in that organization.

Profile — One end-client record. Can narrow enforcement scope: yes — but only for requests carrying that ID.

The workspace row deserves emphasis: isolating clients by workspace does not work. The docs explicitly state workspace splitting is insufficient and recommend creating a separate organization for end-client traffic.

Profiles have no quotas and do not partition data across regions. However, the programs field records the entity's status in Anthropic programs (Cyber Verification Program, Enterprise Frontier Safeguards) which can change retention, encryption, and storage arrangements — a separate approval path not automatically granted by your gateway. Profiles also do not affect billing or pricing; requests remain standard inference requests.

access_type Declares Your Commercial Model

access_type Values

application — Represents a registered user of your product. Default; used when access_type is omitted from the request.

passthrough — Represents the company you resell inference to. Must be sent explicitly; one profile per company, not per person.

Choosing wrong misdirects enforcement: modeling a resold company as multiple application profiles splits one company's behavior across many records so enforcement hits only one; modeling multiple product users as a single passthrough profile means enforcement on that profile stops the entire company. For passthrough, a specific person inside the company can be identified via the request-body metadata.user_id (optional, not the profile's metadata field). Company-level profile plus request-level user ID together pinpoint a person.

What Enforcement on a Profile Looks Like

enforcement_status

has three values: unrestricted (no active enforcement), restricted (at least one active non-ban enforcement), banned (ban active). enforcement_actions lists active enforcements; each carries type (restriction or ban), enac_ -prefixed ID, reason (fixed enum: unsupported_region, fraud_or_abuse, high_harm, usage_policy_violation, account_compromise, unspecified), opened_at, expires_at, and action (what the end client can do to clear it; null means nothing). Enforcement causes Anthropic to reject some or all requests bearing that profile ID — not necessarily all, which affects how you describe availability to customers.

Two fields are easily confused: external_user_details.account_status is your decision ( active, suspended, blocked); enforcement_status is Anthropic's. They are not synced automatically. Upgrading note: if requests still carry the beta header user-profiles-2026-09-04 or earlier, the response omits these two fields and filtering by enforcement_status[] returns 400. For reconciliation, updated_at is not guaranteed to change on enforcement status changes — polling must read the fields directly.

Where to Create, Store, and Inject Profiles

Create — Only in One Place

During customer registration, once. POST /v1/user_profiles is not idempotent; reference_id is not unique. Putting creation in the request path creates a new record per request and hits the creation rate limit. Use your stable identifier for reference_id; uniqueness is your system's responsibility.

Store — On the Customer Record

The uprof_ ID belongs on the customer record; service instances read from there. The docs explicitly recommend this. In multi-replica deployments, if one replica creates its own profile while others read the customer record, the same client ends up with two profiles, splitting attribution and enforcement; the orphaned profile's enforcement becomes invisible.

Inject — On the Outbound Request Header

Header name: anthropic-user-profile-id; SDK/CLI use user_profile_id parameter. Behaves consistently across token counting, Message Batches, and OpenAI SDK compatible requests, so multi-protocol gateways need only one attribution design.

Gateway Position

Cannot pass through from inbound requests — clients could spoof another's profile ID and shift enforcement onto them. Correct flow: strip the header on ingress, authenticate and resolve tenant, look up mapping, write header on egress. If mapping missing, reject the request — do not fall back to sending without an ID. Sending without ID silently returns enforcement risk to the whole organization, the hardest degradation to detect.

// Look up mapping before egress; reject if missing, don't degrade to no-ID
func (t *TenantTransport) RoundTrip(r *http.Request) (*http.Response, error) {
    tenant, ok := tenantFrom(r.Context())
    if !ok {
        return nil, errNoTenant
    }
    profileID, ok := t.profiles.Lookup(tenant)
    if !ok {
        return nil, errNoProfile
    }
    r = r.Clone(r.Context())
    r.Header.Set("anthropic-user-profile-id", profileID)
    return t.base.RoundTrip(r)
}

Cross-Organization Restriction

A profile is only accepted by the organization that created it. Using the same ID in a different organization returns 400 invalid_request_error. If part of a client's traffic goes to Claude API and part to Claude Platform on AWS, each needs its own profile and the mapping table must be partitioned by organization. No config exists to share profiles across organizations — this is an identity scope to design into topology upfront.

Requests That Leak Attribution

Even with correct design, several request categories silently lose attribution — not implementation bugs but mechanism seams:

Requests without an ID. Docs treat these as your own usage. They recommend putting internal workloads in a separate organization so enforcement on these requests lands only there. If offline eval, internal tools, and client traffic share an organization, profiles cannot prevent enforcement spillover.

Outbound paths bypassing the injection point. Queue consumers, offline batch jobs, replicas in other regions, ops scripts — any direct egress path leaks requests that won't error but carry no attribution.

Cross-tenant batching. The header applies per request in a batch, so a batch must contain only one end client's requests. Gateways that batch by request must split batches by profile, otherwise the whole batch is attributed to one client and others' traffic becomes someone else's evidence.

Bedrock and Google Cloud format-only validation. These only check ID format, not existence. Wrong mapping or expired ID returns 200; missing ID also succeeds but unattributed. Mapping errors surface only via self-audit.

10-minute window after deletion. Deleted profiles may still accept requests for ~10 minutes; after that, per-request-verification platforms return 400, but Bedrock and Google Cloud (no lookup) still accept. Deletion and non-effectiveness have a mandatory gap you must handle.

Platform Coverage Gaps

Platform Capabilities

Claude API — Can create profile: Yes. ID location: anthropic-user-profile-id header. Per-request lookup: Yes.

Claude Platform on AWS — Can create profile: Yes. ID location: Same header. Per-request lookup: Yes.

Microsoft Foundry (Anthropic-managed) — Can create profile: Yes. ID location: Same header. Per-request lookup: Yes.

Google Cloud — Can create profile: No — create in the two above. ID location: anthropic-user-profile-id header. Per-request lookup: No — format only.

Claude in Amazon Bedrock — Can create profile: No — create in the two above. ID location: Request-body top-level user_profile_id. Per-request lookup: No — format only.

Claude Platform on AWS's "Yes" for per-request lookup only means it validates ID ownership — enforcement does not take effect there. On AWS, enforcement_status is always unrestricted and enforcement_actions always empty; Anthropic does not reject requests due to active enforcement. If your client traffic primarily runs on AWS, profiles give visibility, not isolation.

Bedrock profiles only work for Claude in Amazon Bedrock (InvokeModel/Converse); older integrations unsupported. ID goes in request body, not header — body often participates in signing, so gateway modification cost is separate. Foundry only supports Anthropic-managed deployments, not Azure-managed.

Each requesting AWS account / GCP project must be linked in the Verification Portal to the profile-creating organization. Only after status shows Linked do program approvals apply to those accounts' requests.

Webhooks: What They Observe, What They Cannot Replace

Organization webhooks ( /v1/organizations/webhooks, beta header webhooks-2026-10-07) emit two events: user_profile.enforcement_action_opened and user_profile.enforcement_action_resolved. Any member can list/view endpoints; only admin/owner/primary owner can create/modify/delete endpoints or rotate signing keys.

Critical beta limitation: event delivery is not yet enabled. Anthropic sends no events; registered endpoints receive nothing. Current state retrieval paths only: GET /v1/user_profiles/{id} for known IDs; list with enforcement_status[]=restricted and enforcement_status[]=banned paging until next_page is null. List may return fewer than limit items or empty pages — empty page ≠ no more data.

Events carry only IDs ( data.id profile ID,

data.enforcement_action_id
enac_

ID, organization_id). To know details, you must retrieve the profile. Events may arrive late or out of order; treat current profile state as source of truth, not event replay.

Even when delivery enables, webhooks cannot replace polling due to structural gaps:

Enforcements already active before delivery enablement or before endpoint registration emit no opened event — only list polling catches them.

Delivery retries a few times then drops; auto-disabled endpoints skip events with no redelivery.

Deleting a profile ends its active enforcements but emits no resolved event.

Endpoint disable conditions include 3xx responses, non-public URL resolution, persistent delivery failures — a redirect or internal address silently stops notifications.

Delivery constraints: 5-second 2xx response required; offload slow work. Deduplicate by webhook-id. Key rotation invalidates old key immediately, including in-flight retries. Max 32 endpoints per organization (disabled count). Prerequisites: organization on Claude API, capability enabled, no HIPAA readiness, default workspace cannot use customer-managed keys.

Observability boundary: webhooks only report "enforcement on your profile". Request rejections themselves generate no events — rejection counts, affected callers, recovery timing must come from your gateway logs. Requests without IDs have no profile to attach events to.

Integration Invariants

Unknown values downgrade per documented rules. Unrecognized enforcement_status → restricted; unrecognized type → restriction; unrecognized reason → unspecified; unrecognized action → null. This fails closed and future-proofs against new enum values.

Do not merge enforcement_status into your account_status . One is Anthropic's decision, the other yours. Mixing them obscures who stopped the client and breaks correct restoration after enforcement lifts — especially if both sides modified the same record.

Pass action field verbatim to the client. It's a string or null (meaning no client-side action). Your role: wait for expires_at or contact Anthropic — do not invent a self-serve appeal flow.

Keep a single creation entry point. Multiple entry points + non-idempotent creation + non-unique reference_id = orphan profiles. Orphan profiles' enforcements are invisible — a silent blind spot.

It Changes Enforcement Granularity, Not Isolation Depth

The mechanism truly changes "one client triggers enforcement on all clients" to "only that client stops". But it only splits Anthropic-side enforcement actions per profile, and only on platforms that verify IDs per request for requests carrying the correct ID. A profile is an attribution record — not an account, not a workspace. The attribution/enforcement mechanism provides no quotas or data partitioning. Retention, encryption, and storage changes come from Cyber Verification Program and Enterprise Frontier Safeguards approvals — a separate, application-gated path.

For expected effect, three conditions must hold simultaneously: end-client traffic in a dedicated organization, profile creation confined to registration flow, gateway as sole egress writing the correct ID on every request. Missing one doesn't zero the mechanism but causes a subset of requests to lose attribution; unattributed requests don't error, they simply revert enforcement risk to the organization on the next enforcement event. The foundation is platforms actually doing per-request lookup: AWS reports unrestricted /empty, Bedrock and Google Cloud only validate format. When client traffic mainly lands there, profiles deliver visibility, not isolation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

API gatewaysecurityGoogle CloudAnthropicBedrockClaude APIenforcementuser profiles
Architecture Development Notes
Written by

Architecture Development Notes

Focused on architecture design, technology trend analysis, and practical development experience sharing.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.