X-Organization-ID header says which organization the request runs against. This page is the reference for how that header is resolved, validated, and enforced — including org-scoped API keys and the realtime handshake equivalent.
For the credentials themselves (API keys versus the Clerk session token), see Auth model: JWT vs API key. For the conceptual model of organizations and membership, see Organizations, roles & membership.
The two axes
A single credential can belong to a user who is a member of several organizations. The credential never picks the organization for you — you select it per request.
Most resources are organization-scoped: workflows, runs, knowledge bases, credentials, integrations, the AI Composer, the Assistant, schedules, and organization settings. Identity-only endpoints — for example
GET /auth/me and GET /auth/me/organizations — do not require the org header.
The header name is
X-Organization-ID with a capital ID. HTTP header lookup is case-insensitive on the wire, but quote this exact casing in code and docs. Response bodies use snake_case (organization_ids, current_organization_id, primary_organization_id).Sending the header
The header value is the organization’s id (a UUID). Add it to any org-scoped request alongside your credential:Org-scoped request
GET /auth/me/organizations. The response carries an organizations array and a total count; use each organization’s id as the header value.
How the header is resolved and enforced
On every org-scoped route the backend runs the same membership check before your handler executes. It reads the header, validates the credential’s org scope, confirms membership, sets the org context on the request, and applies an org-keyed rate limit. The order matters because it determines which error you get.1
Read the header
The backend reads
X-Organization-ID from the request. If it is missing, the request is rejected with 400 and detail X-Organization-ID header is required — before any membership or billing logic runs.2
Check the user is active
An inactive user is rejected with
403 Inactive user.3
Enforce API-key org scope
If the credential is an API key that was scoped to a specific organization at creation, the header must name that same organization. A mismatch returns
403 API key is scoped to a different organization. Keys with no scope skip this check.4
Confirm membership and resolve the role
The backend looks up your role in the named organization. If you are not a member, it returns
403 User is not a member of organization {id}. On success it sets current_organization_id and current_organization_role on the request context (plus a back-compat organization_id alias).5
Apply the org-class rate limit
An organization-keyed
api-class rate limit is checked. It covers both Clerk-JWT and API-key traffic uniformly and fails open on any internal error. Exceeding it returns 429 — see Rate limiting.Error responses
All org-context failures use the standard FastAPI envelope,{"detail": "<message>"}, except the org rate-limit denial, whose detail is a structured object. See Errors & status codes for the full envelope reference.
400 — missing org header
403 — not a member
A missing org header is a
400 (the header is required and absent), not a 403 (membership/permission). A 403 means the header was present but you may not act in that organization. Reserve 404 for the resource not existing within the org you named.DenialEnvelope ({code, layer, key, current, limit, reason}, returned as 402 / 403 / 429) is a separate mechanism that applies only to run and managed-usage surfaces — workflow runs, the Composer, the Assistant, and managed knowledge — never to plain CRUD or org-settings routes. Org-context failures above are not billing denials. See Usage gating & limits.
Per-request override
The organization is not pinned to your client. You choose it per request, with a clear precedence: a value passed on the call wins over the client default.
Both SDKs resolve the per-request value first and fall back to the client default. When neither is set, the header is omitted entirely — which is correct for identity-only endpoints and a
400 on org-scoped ones.
Header org scope vs. body organization_id
Two different things share the word “organization”, and conflating them is the most common org-context mistake.
X-Organization-ID (header)
The organization you are acting in for this request. Resolved and enforced per the steps above. Applies to nearly every org-scoped endpoint.
organization_id (request body)
On a few endpoints (for example, creating an org-scoped API key), a body field that sets which organization owns the new resource. It is independent of the header.
“Which org owns this new resource” (
organization_id in the body) is not the same as “which org am I acting in” (X-Organization-ID in the header). They can name different organizations on the same request.Org-scoped API keys
An API key is owned by a user and can optionally be scoped to one organization when you create it. Scope is set with theorganization_id field in the create body and is independent of the X-Organization-ID header you send on later requests.
string | null
default:"null"
The organization to scope the key to. The caller must be an active member of that organization. When
null (the default), the key works across all of your organizations, and you choose the organization per request with X-Organization-ID.Create an org-scoped key
The create response returns the scope it was given:
string | null
The organization the key is scoped to, or
null for all of your organizations.Roles within an organization
Membership alone is enough for most reads and writes, but some surfaces require a privileged role. The live organization roles areowner and admin.
The
member role is retired and is not a current first-class role. Document and design against owner / admin only. Legacy member rows may still exist and the role name can still appear in some list filters and in the realtime read-gate, but the REST edge rejects it.owner or admin. A membership-only call to one of these returns 403. See Roles & permissions for the per-endpoint matrix and Organizations, roles & membership for the concept.
Org context in realtime
The Socket.io collaboration server carries organization scope as a handshake field, not an HTTP header. The handshakeauth object must include both token (a Clerk JWT) and organizationId; either one missing rejects the entire connection.
Socket.io handshake
org:<organizationId> room and scopes all collaboration traffic to that organization.
Realtime membership is cached server-side with a short TTL, so a role or membership change can take up to a few minutes to take effect on an open socket. The REST surface re-checks membership on every request and has no such lag.
Practical guidance
- Always send the header on org-scoped routes. When in doubt, send it — only identity endpoints (
/auth/me,/auth/me/organizations) are safe without it. - Discover ids dynamically. Resolve organization ids with
GET /auth/me/organizationsrather than hard-coding them, so the code keeps working as a user joins or leaves organizations. - Match the key scope to the deployment. Use an unscoped key for tooling that spans organizations, and a scoped key for automation that should only ever touch one organization.
- Distinguish the two
organization_ids. The header sets the acting org; a bodyorganization_idsets resource ownership. - Plan for the realtime lag. When you change someone’s membership or role, expect REST to reflect it immediately and open realtime sockets to catch up within a few minutes.
Next steps
Organizations, roles & membership
The conceptual model behind org context.
Authentication
Credentials, key format, and the full org-scope flow.
Roles & permissions
Which actions require owner or admin.
Auth model: JWT vs API key
How the two credential paths differ.