Enterprise
Cursor Tenancy Restriction for Enterprise Networks
Tenancy restriction limits which Cursor organizations and teams a request from your network may use. Your proxy adds one header, x-cursor-allowed-tenants, to traffic for api2.cursor.sh and cursor.com, listing numeric org and team ids such as v1.orgs=1001,1002;teams=70. Cursor never sets the header, and without it nothing is restricted.

On this page
What does Cursor tenancy restriction do?
Tenancy restriction lets your network decide which Cursor organizations and teams a request is allowed to use. You turn it on by adding one HTTP header to traffic headed for Cursor. There is no switch for it in the dashboard, Cursor never sets the header itself, and a request without the header gets no restriction from this mechanism.
Cursor checks the header on the request in front of it. The value is not stored on the token, so the same account used off your network is not limited by it. That is the property to understand before anything else, because it tells you what this control is for. It governs traffic that passes through your proxy, which in practice means corporate devices on the corporate path, and nothing beyond that.
Device policies such as Allowed Team IDs are separate. The Cursor docs describe this header as the network control, and point to network configuration for proxy, firewall and encryption setup.
The two are easy to confuse because both take team ids. The Allowed Team IDs policy is set on the managed device through MDM, while this header is added on the network path, so each one covers traffic the other never sees.
This is covered hands-on in Teams and Enterprise Admin — 6 short Units, free to read.
Rather do it than read about it? Run 11 interactive Cursor walkthroughs in a simulated editor. Free, no account needed.
How do you send the x-cursor-allowed-tenants header?
Put the header on requests to Cursor's API at api2.cursor.sh, sign-in included, and to cursor.com. The desktop app, the CLI and API keys all talk to the API, while the website talks to cursor.com, so a header that only reaches the browser page leaves the app and the CLI uncovered.
- Field
- Header name
- Value
x-cursor-allowed-tenants
- Field
- Header value
- Value
- Plain ASCII starting with
v1., for examplev1.orgs=1001,1002;teams=70
- Field
- Hosts
- Value
api2.cursor.sh(including sign-in) andcursor.com
- Field
- Where to add it
- Value
- On the network path, after the client has built the request
- Field
- Copies
- Value
- Up to eight, as repeated headers or joined with a comma before the next
v1.
| Field | Value |
|---|---|
| Header name | x-cursor-allowed-tenants |
| Header value | Plain ASCII starting with v1., for example v1.orgs=1001,1002;teams=70 |
| Hosts | api2.cursor.sh (including sign-in) and cursor.com |
| Where to add it | On the network path, after the client has built the request |
| Copies | Up to eight, as repeated headers or joined with a comma before the next v1. |
The order of work is short, and the first step is the one people tend to rush.
- 1Copy each team id and organization id you want to allow. Use the numeric ids, not names or slugs.
- 2Build one header value that starts with
v1.and lists the ids. - 3Inject
x-cursor-allowed-tenantson the proxy forapi2.cursor.shandcursor.com, after the client builds the request.
Where you add it matters more than it looks. The docs name a TLS-terminating proxy as the reliable place. A managed-browser policy that makes the app itself send the header can fail the desktop sign-in check in the browser before Cursor ever reads the header, which is, I think, the failure most likely to cost someone an afternoon, since nothing about it points back at the header.
Multiple copies narrow rather than widen. Every copy must allow the request, so a second proxy further along the path can only shrink the allowed set. A blank value is refused, and so is a value that breaks the format. Omitting the header entirely is not refused. Cursor does not treat a bad header as no restriction.
What format does the header value use?
One copy is a version prefix followed by up to two lists. The parser is strict on purpose, so the rules below are worth checking against your value before it reaches the fleet.
v1.orgs=<org ids>;teams=<team ids> # examples v1.orgs=1001,1002;teams=70 v1.teams=70 v1.orgs=1001,1002 # two copies joined in one value v1.orgs=1001,1002, v1.teams=70
- The value starts with
v1.. Any other version is refused. - The only keys are
orgsandteams. Either may be left out, at least one must contain an id, and each key may appear once. - Ids are separated by commas. Spaces around an id, a key or
=are ignored. - An organization id is 1 to 19 digits, greater than zero, and at most
9223372036854775807. - A team id is digits only, greater than zero, and at most
9007199254740991. - Names, email addresses, domains, plus or minus signs, decimals,
0, an empty list such asv1.orgs=and a repeated key are all refused. - One copy may list at most 32 ids across both lists and may be at most 1024 bytes.
The joined two-copy example reads differently from the single copy, and that trips people up. With v1.orgs=1001,1002, v1.teams=70 the account must match organization 1001 or 1002 and must also match team 70. Inside one copy any match is enough, across copies every copy has to pass, so splitting a list into two copies quietly turns an or into an and.
Which accounts and API keys does the header allow?
For a person, including a user API key, a copy allows the account when any one of three membership tests passes. Every copy has to allow them.
- They have an active membership in a listed team.
- They have a direct membership in a listed organization.
- They belong to a team that is linked to a listed organization.
Membership alone does not settle it when the client names a team. If the Cursor client also sends x-cursor-team-id, that team must itself be listed, or linked to a listed organization, on every copy. Being a member of an allowed team does not let a request act as a team that is not allowed. When the client has not chosen a team and the account's current team falls outside the list, Cursor drops that team from the request and carries on with an allowed membership.
API keys follow the same idea with one asymmetry. A team API key passes when its team is listed, or linked to a listed organization, on every copy. An organization API key passes only when its organization id is in orgs on every copy, so a teams-only header will refuse it. A request that carries the header but no account is refused outright.
Where do you find the team and organization ids?
The team id is easy to find and the organization id is not, which is probably the most practical thing on this page. Both have to be the numeric ids.
- Team id (`teams`)
- Team settings, team profile, the row labeled Team ID with Copy ID. The organization overview also has Copy team ID in each team's actions menu.
- Organization id (`orgs`)
- Not shown in settings. Open an event in the audit log; if it lists Organization ID as a positive number, that number is the id.
- Not the id
- The team name, the slug, and the Organization ID on the organization overview, which starts with
org_and is a public id the header refuses.
The org_ value is the trap. It sits on the organization overview labeled Organization ID, it looks exactly like what you want, and the header refuses it. Go to the audit log instead and open an event. A missing field just means that event did not record one, so try another. Compliance and monitoring covers how to reach the audit log.
What does a blocked user see?
When the account is outside the list, Cursor denies the request with the error key tenant_restriction_violation. The message names the restriction and repeats the numeric ids from the header. Cursor does not look up names, so users see 1001, not your organization's name.
This network restricts Cursor to specific organizations. Your account is not a member of an organization or team allowed on this network (allowed org ids: 1001, 1002; team ids: 70). Sign in with an allowed account, or contact your network administrator.
Each surface reports it a little differently, which matters if you are writing a helpdesk runbook or a monitoring rule.
- Surface
- cursor.com
- What comes back
- A page titled "This network restricts Cursor to specific organizations" with a Switch account button
- Surface
- Session check
- What comes back
- HTTP 403, header
x-cursor-policy-violation: tenant_restriction_violation, JSONerrorandmessage
- Surface
- API calls
- What comes back
- Permission denied,
ERROR_TENANT_RESTRICTION_VIOLATION, title "Restricted network", not a retry
- Surface
POST /auth/poll- What comes back
- HTTP 403 with
errorandmessage; Cursor cancels that login
- Surface
POST /oauth/token- What comes back
- HTTP 200 with empty tokens and
shouldLogout: true
- Surface
POST /exchange_user_api_key- What comes back
- HTTP 403 with the same
errorandmessage
| Surface | What comes back |
|---|---|
| cursor.com | A page titled "This network restricts Cursor to specific organizations" with a Switch account button |
| Session check | HTTP 403, header x-cursor-policy-violation: tenant_restriction_violation, JSON error and message |
| API calls | Permission denied, ERROR_TENANT_RESTRICTION_VIOLATION, title "Restricted network", not a retry |
POST /auth/poll | HTTP 403 with error and message; Cursor cancels that login |
POST /oauth/token | HTTP 200 with empty tokens and shouldLogout: true |
POST /exchange_user_api_key | HTTP 403 with the same error and message |
When the lists parsed, API responses also carry `x-cursor-tenant-allowed-orgs` and `x-cursor-tenant-allowed-teams`.
One row deserves a second look: the token refresh answers HTTP 200, and the sign-out signal is shouldLogout. A rule that watches only for 403s will miss it. A header refused as malformed produces the same two sentences without the parentheses, so a message with no ids in it usually points at the format rather than the account.
A blocked sign-in can stay on the waiting screen, and a blocked refresh signs the user out without the explanation.
That gap is the detail most likely to reach your helpdesk as something else. From the desktop app, a user outside the list sees a stuck sign-in or an unexplained sign-out, while cursor.com shows the full page and session-check message described above.
Frequently asked questions
Does tenancy restriction follow a user off the corporate network?
No. Cursor checks the header on each request, and the value is not stored on the token. The same account used on a network that does not add the header is not limited by it.
Can I use the Organization ID that starts with org_?
No. That is a public id and the header refuses it. Use the numeric organization id, which you can read from an event in the audit log when it lists Organization ID as a positive number.
What happens if the header value is malformed?
Cursor refuses the request. A blank or malformed value is never treated as no restriction. Only omitting the header entirely leaves requests unrestricted.
Sources & last verified
- Cursor docs: Tenancy Restriction
- Cursor docs: Network configuration
- Cursor docs: Identity and access management
- Cursor docs: Compliance and monitoring (audit logs)
Cursor ships frequently. Facts verified against primary sources on October 25, 2026.