Admin API
The Admin API lets you programmatically access your team's data, including member information, usage metrics, spending details, Team directory groups, model access, and Grok Bot.
- The Admin API uses Basic Authentication with your API key as the username.
- For details on creating API keys, authentication methods, rate limits, and best practices, see the API Overview.
For org-wide actions across your teams, see Organizations and the Organization API.
Endpoints
Get Team Members
/teams/membersRetrieve all team members and their details.
Response Fields
teamMembers array
idstring - Encoded user ID for the team member (e.g.,user_PDSPmvukpYgZEDXsoNirw3CFhy)emailstring - Email address of the team membernamestring - Display name of the team memberrolestring - Role in the team (e.g.,member,owner)isRemovedboolean - Whether the member has been removed from the team
curl -X GET https://api.cursor.com/teams/members \ -u YOUR_API_KEY:Response:
{ "teamMembers": [ { "id": "user_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Alex", "email": "developer@company.com", "role": "member", "isRemoved": false }, { "id": "user_kljUvI0ASZORvSEXf9hV0ydcso", "name": "Sam", "email": "admin@company.com", "role": "owner", "isRemoved": false } ]}Get Audit Logs
/teams/audit-logsRetrieve audit log events for your team with filtering. Track team activity, security events, and configuration changes. Rate limited to 20 requests per minute per team. See rate limits and best practices.
Parameters
startTime string | number
endTime string | number
eventTypes string
login, logout, add_user, remove_user, update_user_role, team_settings, mcp_server_config, team_api_key, user_api_key, privacy_mode, user_spend_limit, team_rule, team_repo, team_hook, team_command, create_directory_group, delete_directory_group, update_directory_group, update_directory_group_permissions, add_user_to_directory_group, remove_user_from_directory_group, bugbot_installation, bugbot_installation_settings, bugbot_repo_settings, bugbot_team_rule, bugbot_team_settings, bugbot_bulk_repo_update, grok_bot_created, grok_bot_access_changed, grok_bot_team_setup_manifest, mcp_authentication, slack_account_link, grok_bot_routinesearch string
page number
1pageSize number
100users string
Date range cannot exceed 30 days. Make multiple requests for longer periods.
Date Formats
The startTime and endTime parameters support multiple formats:
- Relative shortcuts:
now,today,yesterday,7d(7 days ago),5h(5 hours ago),300s(300 seconds ago) - ISO 8601 strings:
2024-01-15T12:00:00Zor2024-01-15T10:00:00-05:00 - YYYY-MM-DD format:
2024-01-15(time defaults to 00:00:00 UTC) - Unix timestamps:
1705315200(seconds) or1705315200000(milliseconds)
Examples:
?startTime=7d&endTime=now- Last 7 days?startTime=5h&endTime=now- Last 5 hours?startTime=2024-01-15&endTime=2024-01-20- Specific date range?startTime=1705315200000&endTime=1705401600000- Unix timestamps
User Filtering
The users parameter accepts multiple formats, comma-separated:
- Email addresses:
developer@company.com,admin@company.com - Encoded user IDs:
user_PDSPmvukpYgZEDXsoNirw3CFhy,user_kljUvI0ASZORvSEXf9hV0ydcso
You can mix formats: developer@company.com,12345,user_PDSPmvukpYgZEDXsoNirw3CFhy
Maximum number of users per request equals pageSize.
curl -X GET "https://api.cursor.com/teams/audit-logs?users=admin@company.com,developer@company.com&eventTypes=login,add_user" \ -u YOUR_API_KEY:Response:
Each object in events includes application_type: grok_bot for Grok Bot, cursor for other Cursor surfaces, or an empty string when the application cannot be determined (including rows written before this field existed).
{ "events": [ { "event_id": "evt_abc123", "timestamp": "2024-01-15T12:30:00.000Z", "ip_address": "203.0.113.42", "user_email": "admin@company.com", "event_type": "add_user", "application_type": "cursor", "event_data": { "email": "admin@company.com", "method": "manual" } }, { "event_id": "evt_def456", "timestamp": "2024-01-15T10:15:00.000Z", "ip_address": "192.168.1.1", "user_email": "developer@company.com", "event_type": "login", "application_type": "grok_bot", "event_data": { "ip_address": "192.168.1.1", "user_agent": "Cursor/0.42.0" } } ], "pagination": { "page": 1, "pageSize": 100, "totalCount": 2, "totalPages": 1, "hasNextPage": false, "hasPreviousPage": false }, "params": { "teamId": 12345, "startDate": 1704729600000, "endDate": 1705334400000 }}Get Daily Usage Data
/teams/daily-usage-dataRetrieve daily usage metrics for your team. Data is aggregated at the hourly level - we recommend polling this endpoint at most once per hour. Rate limited to 20 requests per minute per team. See best practices.
Parameters
startDate number Required
endDate number Required
page number
pageSize, enables pagination and returns data for all team members with a membership during the requested date range.pageSize number
page, enables pagination and returns data for all team members with a membership during the requested date range.Without pagination parameters, this endpoint only returns active users (those with activity during the date range). To get all team members, include both page and pageSize parameters.
When using pagination, the response includes an isActive field for each user indicating whether they had activity on that day. Members who joined after the requested period are excluded.
Date range cannot exceed 30 days. Make multiple requests for longer periods.
The fields subscriptionIncludedReqs, usageBasedReqs, and apiKeyReqs count raw usage events, not billable request units in older request-based pricing. To get accurate billable request counts, use the /teams/filtered-usage-events endpoint and sum the requestsCosts field.
Response Fields
Each object in the data array contains:
userIdnumber - Unique identifier for the userdaystring - The date this record covers (ISO date, e.g.,2024-03-18)datenumber - Date as epoch millisecondsemailstring - User's email addressisActiveboolean - Whether the user had activity on this day (only present with pagination)totalLinesAddednumber - Total lines of code addedtotalLinesDeletednumber - Total lines of code deletedacceptedLinesAddednumber - AI-suggested lines added that were acceptedacceptedLinesDeletednumber - AI-suggested lines deleted that were acceptedtotalAppliesnumber - Total AI code apply actionstotalAcceptsnumber - Total accepted AI suggestionstotalRejectsnumber - Total rejected AI suggestionstotalTabsShownnumber - Total Tab completions shown to the usertotalTabsAcceptednumber - Total Tab completions accepted by the usercomposerRequestsnumber - Number of Composer requests madechatRequestsnumber - Number of chat requests madeagentRequestsnumber - Number of Agent mode requests madecmdkUsagesnumber - Number of Cmd+K inline edit usagessubscriptionIncludedReqsnumber - Requests included in the subscription planapiKeyReqsnumber - Requests made via API keyusageBasedReqsnumber - Usage-based (overage) requestsbugbotUsagesnumber - Number of Bugbot usagesmostUsedModelstring | null - Most frequently used AI model for the dayapplyMostUsedExtensionstring | null - Most common file extension for apply actionstabMostUsedExtensionstring | null - Most common file extension for Tab completionsclientVersionstring | null - Cursor client version used
# Get data for active users only (no pagination)curl -X POST https://api.cursor.com/teams/daily-usage-data \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "startDate": 1710720000000, "endDate": 1710892800000 }'# Get data for ALL team members (with pagination)curl -X POST https://api.cursor.com/teams/daily-usage-data \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "startDate": 1710720000000, "endDate": 1710892800000, "page": 1, "pageSize": 1000 }'Response (without pagination - active users only):
{ "data": [ { "userId": 12345, "day": "2024-03-18", "date": 1710720000000, "isActive": true, "totalLinesAdded": 1543, "totalLinesDeleted": 892, "acceptedLinesAdded": 1102, "acceptedLinesDeleted": 645, "totalApplies": 87, "totalAccepts": 73, "totalRejects": 14, "totalTabsShown": 342, "totalTabsAccepted": 289, "composerRequests": 45, "chatRequests": 128, "agentRequests": 12, "cmdkUsages": 67, "subscriptionIncludedReqs": 180, "apiKeyReqs": 0, "usageBasedReqs": 5, "bugbotUsages": 3, "mostUsedModel": "gpt-5", "applyMostUsedExtension": ".tsx", "tabMostUsedExtension": ".ts", "clientVersion": "0.25.1", "email": "developer@company.com" } ], "period": { "startDate": 1710720000000, "endDate": 1710892800000 }}Response (with pagination - all team members):
{ "data": [ { "userId": 12345, "day": "2024-03-18", "date": 1710720000000, "isActive": true, "totalLinesAdded": 1543, "totalLinesDeleted": 892, "acceptedLinesAdded": 1102, "acceptedLinesDeleted": 645, "totalApplies": 87, "totalAccepts": 73, "totalRejects": 14, "totalTabsShown": 342, "totalTabsAccepted": 289, "composerRequests": 45, "chatRequests": 128, "agentRequests": 12, "cmdkUsages": 67, "subscriptionIncludedReqs": 180, "apiKeyReqs": 0, "usageBasedReqs": 5, "bugbotUsages": 3, "mostUsedModel": "gpt-5", "applyMostUsedExtension": ".tsx", "tabMostUsedExtension": ".ts", "clientVersion": "0.25.1", "email": "developer@company.com" }, { "userId": 12346, "day": "2024-03-18", "date": 1710720000000, "isActive": false, "totalLinesAdded": 0, "totalLinesDeleted": 0, "acceptedLinesAdded": 0, "acceptedLinesDeleted": 0, "totalApplies": 0, "totalAccepts": 0, "totalRejects": 0, "totalTabsShown": 0, "totalTabsAccepted": 0, "composerRequests": 0, "chatRequests": 0, "agentRequests": 0, "cmdkUsages": 0, "subscriptionIncludedReqs": 0, "apiKeyReqs": 0, "usageBasedReqs": 0, "bugbotUsages": 0, "mostUsedModel": null, "applyMostUsedExtension": null, "tabMostUsedExtension": null, "clientVersion": null, "email": "inactive-user@company.com" } ], "period": { "startDate": 1710720000000, "endDate": 1710892800000 }, "pagination": { "page": 1, "pageSize": 1000, "totalUsers": 150, "totalPages": 1, "hasNextPage": false, "hasPreviousPage": false }}Get Spending Data
/teams/spendRetrieve spending information for the current billing cycle with search, sorting, and pagination.
Parameters
searchTerm string
sortBy string
amount, date, user. Default: datesortDirection string
asc, desc. Default: descpage number
1pageSize number
Response Fields
Each object in teamMemberSpend contains:
userIdstring - Encoded user ID (e.g.,user_PDSPmvukpYgZEDXsoNirw3CFhy). Shares the same identifier namespace asteamMembers[].idfrom/teams/members.namestring - Display name of the useremailstring - Email address of the userrolestring - Role in the team (e.g.,member,owner)spendCentsnumber - On-demand spend in cents for the current billing cycle (excludes included usage)overallSpendCentsnumber - Total spend in cents for the current billing cycle, including both on-demand and included usagefastPremiumRequestsnumber - Number of usage-based premium requests made during the billing cyclehardLimitOverrideDollarsnumber - Custom hard spending limit override in dollars for this user (0 means no override)monthlyLimitDollarsnumber | null - Monthly spending limit in dollars set for this user, ornullif no limit is seteffectivePerUserLimitDollarsnumber - Currently enforced per-user spending limit in dollars, derived frommonthlyLimitDollarsandhardLimitOverrideDollars
On June 4th, 2026 we added additional precision to the spendCents and overallSpendCents fields to avoid rounding errors when comparing results to invoice amounts.
curl -X POST https://api.cursor.com/teams/spend \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "searchTerm": "alex@company.com", "page": 2, "pageSize": 25 }'Response:
{ "teamMemberSpend": [ { "userId": "user_PDSPmvukpYgZEDXsoNirw3CFhy", "spendCents": 2450.125487, "overallSpendCents": 2450.125487, "fastPremiumRequests": 1250, "name": "Alex", "email": "developer@company.com", "role": "member", "hardLimitOverrideDollars": 100, "monthlyLimitDollars": 200, "effectivePerUserLimitDollars": 100 }, { "userId": "user_kljUvI0ASZORvSEXf9hV0ydcso", "spendCents": 1875.500123, "overallSpendCents": 3200.750456, "fastPremiumRequests": 980, "name": "Sam", "email": "admin@company.com", "role": "owner", "hardLimitOverrideDollars": 0, "monthlyLimitDollars": null, "effectivePerUserLimitDollars": 50 } ], "subscriptionCycleStart": 1708992000000, "totalMembers": 15, "totalPages": 1}Get Usage Events Data
/teams/filtered-usage-eventsRetrieve detailed usage events for your team with filtering, search, and pagination options. This endpoint provides granular insights into API calls, model usage, token consumption, and costs. Data is aggregated at the hourly level. We recommend polling this endpoint at most once per hour. Rate limited to 60 requests per minute per team. See the API guidance.
Cost Calculation: To reconcile event-level costs with /teams/spend totals, sum the chargedCents field across events. This field includes both the model cost and the Cursor Token Rate when a request is eligible for the rate, matching the dashboard totals. It works for both token-based and request-based billing plans.
The cursorTokenFee field represents the Cursor Token Rate and is only present when the rate applies to a third-party model request. This includes when Auto routes to a third-party model. First-party Cursor models such as Grok and Composer, and request-based enterprise accounts do not include this fee. See Cursor Token Rate.
Parameters
startDate number
endDate number
startDate and endDate are points in time with millisecond precision, and
both bounds are inclusive. An event exactly at 2026-05-08T00:00:00.000Z is
included when endDate is 1778198400000. For non-overlapping daily
ingestion windows, set the previous window's endDate to the final
millisecond of the day, such as 2026-05-07T23:59:59.999Z.
userId number
page number
1pageSize number
100. Maximum: 1000.email string
serviceAccountId string
cloudAgentId string
* to return events from all cloud agent runs.automationId string
* to return events from all automations.hostingType string
CLOUD- Cursor-hosted runsSELF_HOSTED- any self-hosted run (a Team Pool worker or a My Machines worker)SELF_HOSTED_POOL- Team Pool workers onlySELF_HOSTED_MACHINE- personal "My Machine" workers only
An unrecognized hostingType value returns a 400 error rather than an empty result, so a typo can't be mistaken for genuinely zero self-hosted spend. This filter covers inference spend only; self-hosted compute runs on your own machines and is never metered by Cursor.
When you pass multiple filters, the endpoint combines them with AND. For example, automationId and serviceAccountId return events that match both values.
Response Fields
Each object in usageEvents contains:
timestampstring - Event timestamp in epoch milliseconds (as a string)userEmailstring - Email address of the user who made the requestserviceAccountIdstring | undefined - ID of the service account that made the request. Omitted for human user events.serviceAccountNamestring | undefined - Display name of the service account that made the request. Omitted for human user events.cloudAgentIdstring | undefined - ID of the cloud agent run attributed to this event. Omitted for events outside cloud agents.automationIdstring | undefined - UUID of the automation attributed to this event. Omitted for events outside automations.conversationIdstring | undefined - ID of the conversation (agent session) that generated this event. Use it to attribute spend to a session or as a join key with other sources that expose conversation IDs, such as the AI Code Tracking API. Omitted for events without an associated conversation.modelstring - AI model used for the requestkindstring - Billing category (e.g.,Usage-based,Included in Business)maxModeboolean - Whether the request used max moderequestsCostsnumber - Cost in request unitsisTokenBasedCallboolean - Whether the request was billed by token usageisChargeableboolean - Whether this event incurs a chargeisHeadlessboolean - Whether this request was made without a connected client (e.g., background agents)tokenUsageobject | undefined - Token usage details (present whenisTokenBasedCallistrue):inputTokensnumber - Input tokens consumedoutputTokensnumber - Output tokens generatedcacheWriteTokensnumber - Tokens written to cachecacheReadTokensnumber - Tokens read from cachetotalCentsnumber - Total model cost in centsdiscountPercentOffnumber | undefined - Discount percentage applied, if any
chargedCentsnumber - Total amount charged in cents for this event. For third-party model requests subject to the Cursor Token Rate, this includes model cost plus the Cursor Token Rate. Use this field to reconcile event-level costs with/teams/spendtotals. Works for both token-based and request-based billing plans.cursorTokenFeenumber | undefined - Cursor Token Rate in cents. Present only when the rate applies to a third-party model request (including when Auto routes to a third-party model).
curl -X POST https://api.cursor.com/teams/filtered-usage-events \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "startDate": 1748411762359, "endDate": 1751003762359, "email": "developer@company.com", "page": 1, "pageSize": 25 }'Response:
{ "totalUsageEventsCount": 113, "pagination": { "numPages": 5, "currentPage": 1, "pageSize": 25, "hasNextPage": true, "hasPreviousPage": false }, "usageEvents": [ { "timestamp": "1750979225854", "userEmail": "developer@company.com", "conversationId": "8f2e4a1b-6c3d-4e5f-9a7b-2d1c8e6f4a3b", "model": "claude-4.5-sonnet", "kind": "Usage-based", "maxMode": true, "requestsCosts": 5, "isTokenBasedCall": true, "isChargeable": true, "isHeadless": false, "tokenUsage": { "inputTokens": 126, "outputTokens": 450, "cacheWriteTokens": 6112, "cacheReadTokens": 11964, "totalCents": 20.18232 }, "chargedCents": 21.36232, "cursorTokenFee": 1.18 }, { "timestamp": "1750979173824", "userEmail": "developer@company.com", "conversationId": "8f2e4a1b-6c3d-4e5f-9a7b-2d1c8e6f4a3b", "model": "claude-4.5-sonnet", "kind": "Usage-based", "maxMode": true, "requestsCosts": 10, "isTokenBasedCall": true, "isChargeable": true, "isHeadless": false, "tokenUsage": { "inputTokens": 5805, "outputTokens": 311, "cacheWriteTokens": 11964, "cacheReadTokens": 0, "totalCents": 40.167, "discountPercentOff": 10 }, "chargedCents": 37.33, "cursorTokenFee": 1.18 }, { "timestamp": "1750978339901", "userEmail": "admin@company.com", "model": "claude-4-sonnet-thinking", "kind": "Included in Business", "maxMode": true, "requestsCosts": 1.4, "isTokenBasedCall": false, "isChargeable": false, "isHeadless": false, "chargedCents": 8 } ], "period": { "startDate": 1748411762359, "endDate": 1751003762359 }}Service account usage example:
curl -X POST https://api.cursor.com/teams/filtered-usage-events \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "startDate": 1748411762359, "endDate": 1751003762359, "serviceAccountId": "sa_abc123", "page": 1, "pageSize": 10 }'Service account response:
{ "totalUsageEventsCount": 1, "pagination": { "numPages": 1, "currentPage": 1, "pageSize": 10, "hasNextPage": false, "hasPreviousPage": false }, "usageEvents": [ { "timestamp": "1750979225854", "userEmail": "agent-runner@company.com", "serviceAccountId": "sa_abc123", "serviceAccountName": "Nightly CI Agent", "conversationId": "3b9d7c2e-1f4a-4b8c-a6d5-e9f0a2b4c6d8", "model": "claude-4.5-sonnet", "kind": "Usage-based", "maxMode": true, "requestsCosts": 5, "isTokenBasedCall": true, "isChargeable": true, "isHeadless": true, "tokenUsage": { "inputTokens": 126, "outputTokens": 450, "cacheWriteTokens": 6112, "cacheReadTokens": 11964, "totalCents": 20.18232 }, "chargedCents": 21.36232, "cursorTokenFee": 1.18 } ], "period": { "startDate": 1748411762359, "endDate": 1751003762359 }}Automation usage example:
Use an automation UUID to retrieve its usage events. Automation attribution works for automations that run as a user or a service account.
curl -X POST https://api.cursor.com/teams/filtered-usage-events \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "startDate": 1748411762359, "endDate": 1751003762359, "automationId": "7fc64f90-6d7a-4a5d-91b1-bd1f529a85dd", "page": 1, "pageSize": 100 }'Each matching event includes its automationId and cloudAgentId. Sum chargedCents across the events to calculate the automation's total cost.
Self-hosted agent spend example:
curl -X POST https://api.cursor.com/teams/filtered-usage-events \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "startDate": 1748411762359, "endDate": 1751003762359, "hostingType": "SELF_HOSTED", "page": 1, "pageSize": 10 }'Set User Spend Limit
/teams/user-spend-limitSet spending limits for individual team members. This allows you to control how much each user can spend on AI usage within your team. Rate limited to 250 requests per minute per team. See rate limits.
To update up to 100 members per request, use Set User Spend Limits in Bulk (Preview).
Parameters
userEmail string Required
spendLimitDollars number | null Required
null to remove the limit.- Availability: Enterprise only
- The user must already be a member of your team
- Only integer values are accepted (no decimal amounts)
- Setting
spendLimitDollarsto 0 will set the limit to $0 - Setting
spendLimitDollarstonullwill clear/remove the limit entirely
curl -X POST https://api.cursor.com/teams/user-spend-limit \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "userEmail": "developer@company.com", "spendLimitDollars": 100 }'Successful response:
{ "outcome": "success", "message": "Spend limit set to $100 for user developer@company.com"}Error response:
{ "outcome": "error", "message": "Invalid email format"}Set User Spend Limits in Bulk (Preview)
/teams/user-spend-limitsSet spending limits for up to 100 team members in one request. Rate limited to 20 requests per minute per team. See rate limits.
This bulk route is in preview and may change. Request shape, response fields, and error behavior can shift before general availability.
Parameters
updates array Required
userEmailstring - Email address of the team memberspendLimitDollarsnumber | null - Integer spending limit in dollars. Set tonullto remove the limit.
Response Fields
requestedCountnumber - Number of updates in the requestupdatedCountnumber - Number of limits that changedunchangedCountnumber - Number of limits already set to the requested valuefailedCountnumber - Number of updates Cursor could not applyresultsarray - Results in request order. Each result includesuserEmailand a status ofupdated,unchanged, orfailed. Failed results also include anerrormessage.
- Availability: Enterprise only. The bulk endpoint is rolling out; teams that are not yet enabled receive a
403response - A missing team member produces a
failedresult without blocking other updates - Invalid request fields, duplicate emails, or more than 100 updates return a
400response without applying any updates - Repeating a successful update returns
unchangedand does not create another audit event
curl -X POST https://api.cursor.com/teams/user-spend-limits \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "updates": [ { "userEmail": "developer@company.com", "spendLimitDollars": 100 }, { "userEmail": "contractor@company.com", "spendLimitDollars": null }, { "userEmail": "former-employee@company.com", "spendLimitDollars": 50 } ] }'Response:
{ "requestedCount": 3, "updatedCount": 1, "unchangedCount": 1, "failedCount": 1, "results": [ { "userEmail": "developer@company.com", "status": "updated" }, { "userEmail": "contractor@company.com", "status": "unchanged" }, { "userEmail": "former-employee@company.com", "status": "failed", "error": "User not found in team" } ]}Remove Team Member
/teams/remove-memberRemove a member from your team programmatically. This is useful for automating offboarding workflows or integrating with HR systems. Rate limited to 50 requests per minute per team. See rate limits.
Parameters
userId string
user_PDSPmvukpYgZEDXsoNirw3CFhy). Required if email is not provided.email string
userId is not provided.- Availability: Enterprise only
- Provide either
userIdoremail, but not both - At least one paid member must remain on the team after removal
- At least one admin (owner or free-owner) must remain on the team after removal
curl -X POST https://api.cursor.com/teams/remove-member \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "email": "developer@company.com" }'Response:
{ "success": true, "userId": "user_PDSPmvukpYgZEDXsoNirw3CFhy", "hasBillingCycleUsage": true}Remove by user ID:
curl -X POST https://api.cursor.com/teams/remove-member \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "userId": "user_PDSPmvukpYgZEDXsoNirw3CFhy" }'Error responses:
{ "error": "User is not a member of this team"}{ "error": "Either userId or email must be provided"}{ "error": "Only one of userId or email should be provided, not both"}Get Team Repo Blocklists
/settings/repo-blocklists/reposRetrieve all repository blocklists configured for your team. Add repositories and use patterns to prevent files or directories from being used as context.
Pattern Examples
Common blocklist patterns:
*- Block entire repository*.env- Block all .env filesconfig/*- Block all files in config directory**/*.secret- Block all .secret files in any subdirectorysrc/api/keys.ts- Block specific file
curl -X GET https://api.cursor.com/settings/repo-blocklists/repos \ -u YOUR_API_KEY:Response:
{ "repos": [ { "id": "repo_123", "url": "https://github.com/company/sensitive-repo", "patterns": ["*.env", "config/*", "secrets/**"] }, { "id": "repo_456", "url": "https://github.com/company/internal-tools", "patterns": ["*"] } ]}Upsert Repo Blocklists
/settings/repo-blocklists/repos/upsertReplace existing repository blocklists for the provided repos. This endpoint will only overwrite the patterns for the repositories provided. All other repos will be unaffected.
Parameters
repos array Required
Array of repository blocklist objects. Each repository object must contain:
urlstring - Repository URL to blocklistpatternsstring[] - Array of file patterns to block (glob patterns supported)
curl -X POST https://api.cursor.com/settings/repo-blocklists/repos/upsert \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "repos": [ { "url": "https://github.com/company/sensitive-repo", "patterns": ["*.env", "config/*", "secrets/**"] }, { "url": "https://github.com/company/internal-tools", "patterns": ["*"] } ] }'Response:
{ "repos": [ { "id": "repo_123", "url": "https://github.com/company/sensitive-repo", "patterns": ["*.env", "config/*", "secrets/**"] }, { "id": "repo_456", "url": "https://github.com/company/internal-tools", "patterns": ["*"] } ]}Delete Repo Blocklist
/settings/repo-blocklists/repos/:repoIdRemove a specific repository from the blocklist. Returns 204 No Content on successful deletion.
Parameters
repoId string Required
curl -X DELETE https://api.cursor.com/settings/repo-blocklists/repos/repo_123 \ -u YOUR_API_KEY:Response:
204 No ContentTeam directory groups
Team Admin API routes at /teams/directory-groups manage Team directory groups. Those groups set spend and policy within one team. See Organization Groups for how they differ from org-level cohorts and Billing Groups.
Map a group to a team when an Organization Group should drive that team's membership. Create, list, and add or remove members of a Team directory group with a Team API key. For dashboard and SCIM setup, see directory groups.
These routes are a different API from billing groups. Use this table to pick the right path and id:
| Groups | Path | ID |
|---|---|---|
| Organization Groups | /organizations/groups | id uses the g_ prefix. Responses also return publicId with the grp_ prefix. See Organization Groups. |
| Team directory groups | /teams/directory-groups | Public id uses the team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2. |
| Billing Groups | /teams/groups | group_… |
:groupId is the team's directory-group public id. It uses the team_group_… prefix. Do not pass Organization Group g_ or grp_ ids, or Billing Group group_… ids.
- Authentication: Team API key (Basic auth). Reads require
read:*. Writes requireadmin:*. Keys withadmin:*work for both. A write with aread:*key returns401. - Group IDs: Every
:groupIdis the group's public id with theteam_group_…prefix, such asteam_group_01k2ja2000e0080000000000n2. Organization Groups useg_andgrp_. Billing Groups usegroup_…. - Pagination: List routes accept
pageandpageSize. Both values must be positive integers. - Rate limit: Each route allows 20 requests per minute per team. See rate limits and best practices.
- SCIM-synced groups: Manage membership in your identity provider. Member add and remove requests return
400for SCIM-synced groups.
Group routes share these error responses:
| Status | When |
|---|---|
400 | Malformed group ID, pagination value, or request body |
401 | Invalid API key, or the key is missing the read:* (reads) or admin:* (writes) scope |
404 | Group does not exist on this team |
429 | Rate limit exceeded. The response includes a Retry-After: 60 header |
List Team directory groups
/teams/directory-groupsRetrieve Team directory groups for the team attached to your API key.
Query parameters
page number
1.pageSize number
50. Capped at 200; values above 200 are clamped to 200.Response Fields
Each object in groups contains:
idstring - Group public id with theteam_group_…prefix. Use this value as:groupIdon the other routes.namestring - Group namememberCountnumber - Number of members in the groupmonthlySpendingLimitDollarsnumber | null - Monthly spending limit in whole dollars for each group member.nullmeans the group has no limit.createdAtstring - Creation time in ISO 8601 formatupdatedAtstring - Last update time in ISO 8601 format
pagination object
page, pageSize, totalCount, totalPages, hasNextPage, and hasPreviousPage.curl -X GET "https://api.cursor.com/teams/directory-groups?page=1&pageSize=50" \ -u YOUR_API_KEY:Response:
{ "groups": [ { "id": "team_group_01k2ja2000e0080000000000n2", "name": "Engineering", "memberCount": 12, "monthlySpendingLimitDollars": 500, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-20T14:22:00.000Z" }, { "id": "team_group_01k2jb4000e0080000000000p7", "name": "Design", "memberCount": 8, "monthlySpendingLimitDollars": null, "createdAt": "2026-01-16T09:00:00.000Z", "updatedAt": "2026-01-16T09:00:00.000Z" } ], "pagination": { "page": 1, "pageSize": 50, "totalCount": 2, "totalPages": 1, "hasNextPage": false, "hasPreviousPage": false }}Get Team directory group
/teams/directory-groups/:groupIdRetrieve one Team directory group.
Parameters
groupId string Required
team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2. Organization Group g_ or grp_ ids and Billing Group group_… ids return 400 or 404.Response Fields
The group object contains id, name, memberCount, monthlySpendingLimitDollars, createdAt, and updatedAt. These fields match the List Team directory groups response.
curl -X GET https://api.cursor.com/teams/directory-groups/team_group_01k2ja2000e0080000000000n2 \ -u YOUR_API_KEY:Response:
{ "group": { "id": "team_group_01k2ja2000e0080000000000n2", "name": "Engineering", "memberCount": 12, "monthlySpendingLimitDollars": 500, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-20T14:22:00.000Z" }}Create Team directory group
/teams/directory-groupsCreate a Team directory group with manually managed membership. To create a SCIM-synced group, sync it from your identity provider instead. See SCIM.
Request body
name string Required
Response Fields
Returns 201 Created with the new group object. The object contains id, name, memberCount, monthlySpendingLimitDollars, createdAt, and updatedAt. The id is the group's public id with the team_group_… prefix.
Errors
400- The group name is missing, empty, or already used by another active group.
curl -X POST https://api.cursor.com/teams/directory-groups \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "name": "Engineering" }'Response:
{ "group": { "id": "team_group_01k2ja2000e0080000000000n2", "name": "Engineering", "memberCount": 0, "monthlySpendingLimitDollars": null, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" }}Update Team directory group
/teams/directory-groups/:groupIdUpdate a group's name or monthly spending limit. Updates are partial: include at least one field, and any field you omit keeps its current value.
Parameters
groupId string Required
team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2.Request body
name string
monthlySpendingLimitDollars number
0 and 2147483647.clearMonthlySpendingLimitDollars boolean
true to remove the group spending limit. Do not include monthlySpendingLimitDollars in the same request.Response Fields
Returns the updated group object with id, name, memberCount, monthlySpendingLimitDollars, createdAt, and updatedAt.
Errors
400- The request has no update fields, contains an invalid value, uses another active group's name, or sets and clears the spending limit in the same request.
curl -X PATCH https://api.cursor.com/teams/directory-groups/team_group_01k2ja2000e0080000000000n2 \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "name": "Platform Engineering", "monthlySpendingLimitDollars": 500 }'Response:
{ "group": { "id": "team_group_01k2ja2000e0080000000000n2", "name": "Platform Engineering", "memberCount": 12, "monthlySpendingLimitDollars": 500, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-20T14:22:00.000Z" }}Delete Team directory group
/teams/directory-groups/:groupIdDelete a Team directory group. The group must be empty: remove every member before deleting it.
Parameters
groupId string Required
team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2.Response
Returns 204 No Content after deleting the group.
Errors
400- The group still has members, or the group has an active SCIM mapping.
You can't delete a group with an active SCIM mapping through this endpoint. Remove the mapping in the dashboard, remove every member, then delete the group.
curl -X DELETE https://api.cursor.com/teams/directory-groups/team_group_01k2ja2000e0080000000000n2 \ -u YOUR_API_KEY:Response: 204 No Content
List Team directory group members
/teams/directory-groups/:groupId/membersRetrieve members in a Team directory group.
Parameters
groupId string Required
team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2.Query parameters
page number
1.pageSize number
50. Capped at 200; values above 200 are clamped to 200.Response Fields
Each object in members contains:
userIdstring - Public user ID with theuser_prefixnamestring - Display name of the memberemailstring - Email address of the memberjoinedAtstring - Time the member was added to the group in ISO 8601 format
pagination object
page, pageSize, totalCount, totalPages, hasNextPage, and hasPreviousPage.curl -X GET "https://api.cursor.com/teams/directory-groups/team_group_01k2ja2000e0080000000000n2/members?page=1&pageSize=50" \ -u YOUR_API_KEY:Response:
{ "members": [ { "userId": "user_abc123", "name": "Alex Developer", "email": "alex@company.com", "joinedAt": "2026-01-15T10:30:00.000Z" }, { "userId": "user_def456", "name": "Sam Engineer", "email": "sam@company.com", "joinedAt": "2026-01-16T09:15:00.000Z" } ], "pagination": { "page": 1, "pageSize": 50, "totalCount": 2, "totalPages": 1, "hasNextPage": false, "hasPreviousPage": false }}Add Team directory group members
/teams/directory-groups/:groupId/members/bulk-addAdd members to a manual Team directory group.
Parameters
groupId string Required
team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2.Request body
userIds string[] Required
user_ prefix. A single request may include up to 100 users.Response Fields
addedCount number
SCIM-synced groups reject manual membership changes with a 400 response.
Manage their membership in your identity provider.
curl -X POST https://api.cursor.com/teams/directory-groups/team_group_01k2ja2000e0080000000000n2/members/bulk-add \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "userIds": ["user_abc123", "user_def456"] }'Response:
{ "addedCount": 2}Remove Team directory group members
/teams/directory-groups/:groupId/members/bulk-removeRemove members from a manual Team directory group.
Parameters
groupId string Required
team_group_… prefix, such as team_group_01k2ja2000e0080000000000n2.Request body
userIds string[] Required
user_ prefix. A single request may include up to 100 users.Response Fields
removedCount number
SCIM-synced groups reject manual membership changes with a 400 response.
Manage their membership in your identity provider.
curl -X POST https://api.cursor.com/teams/directory-groups/team_group_01k2ja2000e0080000000000n2/members/bulk-remove \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "userIds": ["user_def456"] }'Response:
{ "removedCount": 1}Billing Groups
Billing groups allow Enterprise admins to understand and manage spend across groups of users. This functionality is useful for reporting, internal chargebacks, and budgeting.
Members can only be in one billing group at a time. Members not assigned to any group are placed in a reserved Unassigned group.
Billing Groups live at /teams/groups and use group_… ids. Team directory groups live at /teams/directory-groups and use team_group_… ids. The two APIs do not accept each other's ids.
List Groups
/teams/groupsRetrieve all billing groups for your team with spend data for the current billing cycle.
Parameters
billingCycle string
2025-01-15) to specify which billing cycle to query. Defaults to current cycle.curl -X GET "https://api.cursor.com/teams/groups?billingCycle=2025-01-15" \ -u YOUR_API_KEY:Response:
{ "groups": [ { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Engineering", "type": "BILLING", "directoryGroupId": null, "memberCount": 12, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-20T14:22:00.000Z", "spendCents": 245000, "currentMembers": [ { "userId": "user_abc123", "name": "Alex Developer", "email": "alex@company.com", "joinedAt": "2024-01-15T10:30:00.000Z", "leftAt": null, "spendCents": 12500 } ], "formerMembers": [], "dailySpend": [ { "date": "2025-01-15", "spendCents": 8500 }, { "date": "2025-01-16", "spendCents": 9200 } ] }, { "id": "group_kljUvI0ASZORvSEXf9hV0ydcso", "name": "Design", "type": "BILLING", "directoryGroupId": "dir_group_abc123xyz", "memberCount": 5, "createdAt": "2024-01-16T09:00:00.000Z", "updatedAt": "2024-01-16T09:00:00.000Z", "spendCents": 87500, "currentMembers": [], "formerMembers": [], "dailySpend": [] } ], "unassignedGroup": { "id": "group_unassigned", "name": "Unassigned", "type": "BILLING", "directoryGroupId": null, "memberCount": 3, "createdAt": "2024-01-01T00:00:00.000Z", "updatedAt": "2024-01-01T00:00:00.000Z", "spendCents": 15000, "currentMembers": [], "formerMembers": [], "dailySpend": [] }, "billingCycle": { "cycleStart": "2025-01-01T00:00:00.000Z", "cycleEnd": "2025-02-01T00:00:00.000Z" }}Get Group
/teams/groups/:groupIdRetrieve a single billing group with its members and spend data for the current billing cycle.
Parameters
groupId string Required
group_PDSPmvukpYgZEDXsoNirw3CFhy)billingCycle string
2025-01-15) to specify which billing cycle to query. Defaults to current cycle.curl -X GET "https://api.cursor.com/teams/groups/group_PDSPmvukpYgZEDXsoNirw3CFhy?billingCycle=2025-01-15" \ -u YOUR_API_KEY:Response:
{ "group": { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Engineering", "type": "BILLING", "directoryGroupId": null, "memberCount": 3, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-20T14:22:00.000Z", "spendCents": 125000, "currentMembers": [ { "userId": "user_abc123", "name": "Alex Developer", "email": "alex@company.com", "joinedAt": "2024-01-15T10:30:00.000Z", "leftAt": null, "spendCents": 75000, "dailySpend": [ { "date": "2025-01-15", "spendCents": 5000 }, { "date": "2025-01-16", "spendCents": 7500 } ] }, { "userId": "user_def456", "name": "Sam Engineer", "email": "sam@company.com", "joinedAt": "2024-01-16T09:15:00.000Z", "leftAt": null, "spendCents": 50000, "dailySpend": [ { "date": "2025-01-15", "spendCents": 3500 }, { "date": "2025-01-16", "spendCents": 4200 } ] } ], "formerMembers": [ { "userId": "user_xyz789", "name": "Former Member", "email": "former@company.com", "joinedAt": "2024-01-10T08:00:00.000Z", "leftAt": "2024-01-14T17:00:00.000Z", "spendCents": 0 } ], "dailySpend": [ { "date": "2025-01-15", "spendCents": 8500 }, { "date": "2025-01-16", "spendCents": 11700 } ] }, "billingCycle": { "cycleStart": "2025-01-01T00:00:00.000Z", "cycleEnd": "2025-02-01T00:00:00.000Z" }}Create Group
/teams/groupsCreate a new billing group. Rate limited to 20 requests per minute per team.
Parameters
name string Required
type string
BILLING is supported. Default: BILLINGcurl -X POST https://api.cursor.com/teams/groups \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "name": "Engineering" }'Response:
{ "group": { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Engineering", "type": "BILLING", "directoryGroupId": null, "memberCount": 0, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:00.000Z", "members": [] }}Update Group
/teams/groups/:groupIdUpdate a billing group's name or directory group attachment. Rate limited to 20 requests per minute per team.
Only one field can be updated per request. To update both name and directory attachment, make separate requests.
Parameters
groupId string Required
name string
directoryGroupId string | null
null to detach from directory synccurl -X PATCH https://api.cursor.com/teams/groups/group_PDSPmvukpYgZEDXsoNirw3CFhy \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "name": "Platform Engineering" }'Response:
{ "group": { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Platform Engineering", "type": "BILLING", "directoryGroupId": null, "memberCount": 3, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-25T16:45:00.000Z", "members": [ { "userId": "user_abc123", "name": "Alex Developer", "email": "alex@company.com", "joinedAt": "2024-01-15T10:30:00.000Z" } ] }}Delete Group
/teams/groups/:groupIdDelete a billing group. Returns 204 No Content on success. Rate limited to 20 requests per minute per team.
Deleting a billing group is a destructive operation; data cannot be recovered. All historical usage for deleted groups is reassigned retroactively to the Unassigned group.
Parameters
groupId string Required
curl -X DELETE https://api.cursor.com/teams/groups/group_PDSPmvukpYgZEDXsoNirw3CFhy \ -u YOUR_API_KEY:Response:
204 No ContentAdd Members to Group
/teams/groups/:groupId/membersAdd team members to a billing group. Users must already be members of your team and not currently assigned to another group. Rate limited to 20 requests per minute per team.
Billing groups synced with SCIM cannot be modified via the API. All member assignment for SCIM-synced groups must be handled via SCIM.
Parameters
groupId string Required
userIds string[] Required
["user_abc123", "user_def456"])curl -X POST https://api.cursor.com/teams/groups/group_PDSPmvukpYgZEDXsoNirw3CFhy/members \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "userIds": ["user_abc123", "user_def456"] }'Response:
{ "group": { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Engineering", "type": "BILLING", "directoryGroupId": null, "memberCount": 2, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-25T16:50:00.000Z", "members": [ { "userId": "user_abc123", "name": "Alex Developer", "email": "alex@company.com", "joinedAt": "2024-01-25T16:50:00.000Z" }, { "userId": "user_def456", "name": "Sam Engineer", "email": "sam@company.com", "joinedAt": "2024-01-25T16:50:00.000Z" } ] }}Remove Members from Group
/teams/groups/:groupId/membersRemove team members from a billing group. Removed members are moved to the Unassigned group. Rate limited to 20 requests per minute per team.
Billing groups synced with SCIM cannot be modified via the API. All member changes for SCIM-synced groups must be handled via SCIM.
Parameters
groupId string Required
userIds string[] Required
curl -X DELETE https://api.cursor.com/teams/groups/group_PDSPmvukpYgZEDXsoNirw3CFhy/members \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "userIds": ["user_def456"] }'Response:
{ "group": { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Engineering", "type": "BILLING", "directoryGroupId": null, "memberCount": 1, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-25T17:00:00.000Z", "members": [ { "userId": "user_abc123", "name": "Alex Developer", "email": "alex@company.com", "joinedAt": "2024-01-25T16:50:00.000Z" } ] }}Model access
Model access routes are in preview and may change. Paths, response fields, and error behavior can shift before general availability.
Read and update the team's model access policy: whether a custom policy is on, defaults for new providers and models, per-provider / per-model toggles, and per-model settings such as Fast and reasoning effort.
Enabling a model without parameter settings leaves it on the catalog defaults. Use per-model settings when those defaults, such as Fast, do not match your team's policy.
These routes return the team baseline. Organization Groups can still widen access for some members; group allowlists are not part of this API. Personal API key (BYOK) controls stay in the dashboard.
For org-wide reads and bulk toggles across linked teams, see the Organization API model access routes.
- Availability: Teams with model access control enabled
- Authentication: Team API key (Basic auth). Reads require
models:read. Writes requiremodels:*. Keys withadmin:*work for both. Genericread:*keys cannot call these routes. - Provider and model IDs: Path segments are catalog ids such as
anthropicandclaude-opus-4-6, not display names. GET responses include display names. - Configuration first: Provider and model reads and writes return 409 while
stateisunrestricted(orlegacy). The firstPUT /teams/model-access/configurationwith defaults on an unrestricted team turns policy on and seeds the current catalog (same idea as the first save on the Models page). Later configuration PUTs with defaults update defaults only and leave existing toggles in place. - Return to unrestricted:
PUT /teams/model-access/configurationwith{ "state": "unrestricted" }clears the custom policy sostatebecomesunrestrictedagain. - Rate limits: 20 requests per minute. Writes appear in team audit logs as
team_settingsevents. See rate limits and best practices.
Get Model Access Configuration
/teams/model-access/configurationReturn whether the team has a custom model-access policy and the defaults for newly seen providers and models.
Response Fields
teamId number
state string
unrestricted, custom, or legacy.newProviderDefault string | null
enabled or disabled when state is custom. Otherwise null.newModelDefault string | null
enabled or disabled when state is custom. Otherwise null.curl -X GET https://api.cursor.com/teams/model-access/configuration \ -u YOUR_API_KEY:Response:
{ "teamId": 7, "state": "unrestricted", "newProviderDefault": null, "newModelDefault": null}Update Model Access Configuration
/teams/model-access/configurationCreate a custom policy, update defaults, or return the team to unrestricted.
Send either:
{ "state": "unrestricted" }to clear the custom policy (and legacy allowed/blocked lists) sostatebecomesunrestricted{ "newProviderDefault", "newModelDefault" }to create or update a custom policy (backward-compatible shorthand forstate: "custom")
The first defaults PUT on an unrestricted team creates a custom policy and seeds catalog entries. Later defaults PUTs update defaults only and leave existing toggles in place.
Request body
state string
unrestricted to clear policy. Omit when sending defaults.newProviderDefault string
enabled or disabled. Required when creating or updating a custom policy; omit when state is unrestricted.newModelDefault string
enabled or disabled. Required when creating or updating a custom policy; omit when state is unrestricted.curl -X PUT https://api.cursor.com/teams/model-access/configuration \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "newProviderDefault": "disabled", "newModelDefault": "enabled" }'Response:
{ "teamId": 7, "state": "custom", "newProviderDefault": "disabled", "newModelDefault": "enabled"}Return the team to unrestricted:
curl -X PUT https://api.cursor.com/teams/model-access/configuration \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "state": "unrestricted" }'Response:
{ "teamId": 7, "state": "unrestricted", "newProviderDefault": null, "newModelDefault": null}List Model Access Providers
/teams/model-access/providersList catalog providers and models with resolved enabled flags and per-model parameters. Returns 409 when the team does not have a custom policy.
Each model includes a catalog-driven parameters array. Parameter ids and supported values come from the model catalog (for example fast, reasoning, effort, context). Use this GET to discover which parameters a model supports before writing.
Model parameters fields
id string
fast or reasoning).displayName string
supportedValues string[]
allowedValues string[]
configuredDefaultValue string | null
null when unset.catalogDefaultValue string | null
curl -X GET https://api.cursor.com/teams/model-access/providers \ -u YOUR_API_KEY:Response:
{ "teamId": 7, "state": "custom", "providers": [ { "id": "anthropic", "displayName": "Anthropic", "enabled": true, "models": [ { "id": "claude-opus-4-6", "displayName": "Opus 4.6", "enabled": true, "parameters": [ { "id": "fast", "displayName": "Fast", "supportedValues": ["false", "true"], "allowedValues": ["false", "true"], "configuredDefaultValue": null, "catalogDefaultValue": "true" } ] } ] }, { "id": "openai", "displayName": "OpenAI", "enabled": true, "models": [ { "id": "gpt-5.4", "displayName": "GPT-5.4", "enabled": true, "parameters": [ { "id": "reasoning", "displayName": "Reasoning", "supportedValues": ["low", "medium", "high", "xhigh", "max"], "allowedValues": ["low", "medium", "high"], "configuredDefaultValue": "high", "catalogDefaultValue": "medium" } ] } ] } ]}Update Model Access Provider
/teams/model-access/providers/:providerEnable or disable a provider. Returns 409 when the team is still unrestricted or legacy.
Parameters
provider string Required
openai or anthropic).Request body
enabled boolean Required
curl -X PUT https://api.cursor.com/teams/model-access/providers/openai \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{"enabled": false}'List Models for a Provider
/teams/model-access/providers/:provider/modelsList models for one provider with resolved enabled flags and per-model parameters. The parameter fields match the providers response. Returns 409 when the team does not have a custom policy.
Parameters
provider string Required
anthropic).curl -X GET https://api.cursor.com/teams/model-access/providers/anthropic/models \ -u YOUR_API_KEY:Update Model Access Model
/teams/model-access/providers/:provider/models/:modelEnable or disable a single model, and optionally set per-model parameter restrictions and defaults. Returns 409 when the team is still unrestricted or legacy.
Parameters
provider string Required
anthropic).model string Required
claude-opus-4-6).Request body
enabled boolean Required
parameters object
allowedValuesstring[] | null: Restrict which values members may pick. Passnullto clear the restriction.defaultValuestring | null: Default value for the team. Must be withinallowedValueswhen a restriction is set. Passnullto restore the catalog default.
Unknown parameter ids or values, empty allowedValues arrays, defaults outside allowedValues, and settings that resolve to no valid model variant return 400.
Disable Fast on a model:
curl -X PUT https://api.cursor.com/teams/model-access/providers/anthropic/models/claude-opus-4-6 \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "parameters": { "fast": { "allowedValues": ["false"] } } }'Set allowed reasoning levels and a default:
curl -X PUT https://api.cursor.com/teams/model-access/providers/openai/models/gpt-5.4 \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "parameters": { "reasoning": { "allowedValues": ["low", "medium", "high"], "defaultValue": "high" } } }'Clear a restriction and restore the catalog default:
curl -X PUT https://api.cursor.com/teams/model-access/providers/openai/models/gpt-5.4 \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "parameters": { "reasoning": { "allowedValues": null, "defaultValue": null } } }'Response:
{ "id": "gpt-5.4", "displayName": "GPT-5.4", "enabled": true, "provider": "openai", "parameters": [ { "id": "reasoning", "displayName": "Reasoning", "supportedValues": ["low", "medium", "high", "xhigh", "max"], "allowedValues": ["low", "medium", "high", "xhigh", "max"], "configuredDefaultValue": null, "catalogDefaultValue": "medium" } ]}Errors
Error bodies use:
{ "code": "error", "message": "…" }| Status | When |
|---|---|
401 | Bad key, or missing models:read / models:* (or admin:*) |
403 | Model access control is not available for that team |
409 | Provider or model read or write while state is unrestricted or legacy |
400 | Unknown provider, model, parameter id, or parameter value; invalid body; empty allowedValues; default outside allowedValues; settings that resolve to no valid model variant; or a Smart Auto required model would be blocked |
Grok Bot
Enable Grok Bot and manage capabilities, Enforce Auto-Review, group access, network policy, team rules, and setup scripts.
- Authentication: Team API key (Basic auth). Reads require
read:*oradmin:*. Writes requireadmin:*. A write with aread:*key returns401. - Rate limits: 20 requests per minute per team per endpoint. When you exceed the limit, the API returns
429withRetry-After: 60. See rate limits. - Reads on every plan:
GET /grok-bot/access,/network, and/auto-reviewreturn the effective policy on every plan. Writes return403when the feature is not available to the team.
Enable Grok Bot
/grok-bot/enableEnable Grok Bot for the team. The first enable on an eligible Enterprise team starts the trial. Returns 204 No Content on success.
curl -X POST https://api.cursor.com/grok-bot/enable \ -u YOUR_API_KEY:Response:
204 No ContentDisable Grok Bot
/grok-bot/disableDisable Grok Bot for the team. Members lose access; their computers are not deleted. Returns 403 on Teams plans.
curl -X POST https://api.cursor.com/grok-bot/disable \ -u YOUR_API_KEY:Response:
204 No ContentGet Grok Bot Capabilities
/grok-bot/capabilitiesReturn the team's Grok Bot capabilities.
Response Fields
enabled boolean
cloudAgents boolean
templateSharing string | null
all, team_only, none, or null for the team default.actionRecording boolean
localExecution string | null
never, ask, always, or null for no ceiling.localEgressAllowed boolean
curl -X GET https://api.cursor.com/grok-bot/capabilities \ -u YOUR_API_KEY:Response:
{ "enabled": true, "cloudAgents": true, "templateSharing": "team_only", "actionRecording": false, "localExecution": "ask", "localEgressAllowed": true}Update Grok Bot Capabilities
/grok-bot/capabilitiesUpdate Grok Bot capabilities. Omitted fields stay unchanged. Returns 403 when a field is not available to the team.
enabled is read-only. Use Enable Grok Bot or Disable Grok Bot. Send at least one field.
Parameters
cloudAgents boolean
templateSharing string | null
all, team_only, none, or null to restore the team default.actionRecording boolean
localExecution string | null
never, ask, always, or null to clear the team ceiling.localEgressAllowed boolean
curl -X PATCH https://api.cursor.com/grok-bot/capabilities \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "cloudAgents": false, "localExecution": "never", "localEgressAllowed": false }'Response:
{ "enabled": true, "cloudAgents": false, "templateSharing": "team_only", "actionRecording": false, "localExecution": "never", "localEgressAllowed": false}Get Enforce Auto-Review
/grok-bot/auto-reviewReturn the team's Enforce Auto-Review policy.
Response Fields
enforced boolean
true, every member must keep Enforce Auto-Review on.rules object
allow and block instruction lists that feed Auto Review.curl -X GET https://api.cursor.com/grok-bot/auto-review \ -u YOUR_API_KEY:Response:
{ "enforced": true, "rules": { "allow": ["Read-only git commands"], "block": ["Publishing releases"] }}Replace Enforce Auto-Review
/grok-bot/auto-reviewReplace the team's Enforce Auto-Review policy. Returns 403 when Enforce Auto-Review is not available to the team.
Empty allow and block lists keep stored instructions if your team can't set Auto-Review rules. Non-empty lists return 403 in that case.
Parameters
enforced boolean Required
true, every member must keep Enforce Auto-Review on.rules object Required
allowstring[]: Up to 20 instructions, 1,000 characters each. Trimmed and deduped.blockstring[]: Up to 20 instructions, 1,000 characters each. Trimmed and deduped.
curl -X PUT https://api.cursor.com/grok-bot/auto-review \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "enforced": true, "rules": { "allow": ["Read-only git commands"], "block": ["Publishing releases"] } }'Lock Enforce Auto-Review without changing instructions:
curl -X PUT https://api.cursor.com/grok-bot/auto-review \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "enforced": true, "rules": { "allow": [], "block": [] } }'Response:
{ "enforced": true, "rules": { "allow": ["Read-only git commands"], "block": ["Publishing releases"] }}Get Grok Bot Access
/grok-bot/accessReturn who on the team can use Grok Bot.
Response Fields
mode string
all or limited.groups array
mode is limited. Each item has an encoded id and a name. Empty when mode is all.curl -X GET https://api.cursor.com/grok-bot/access \ -u YOUR_API_KEY:Response:
{ "mode": "limited", "groups": [ { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Platform Engineering" } ]}Update Grok Bot Access
/grok-bot/accessSet who on the team can use Grok Bot. Returns 403 when group access is not available to the team.
Parameters
mode string Required
all for every member, or limited for selected billing groups.groupIds array
mode is limited (1-100, duplicates count once). Omit when mode is all.Unknown or malformed IDs, an empty limited list, or group IDs with all return 400.
curl -X PUT https://api.cursor.com/grok-bot/access \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "mode": "limited", "groupIds": ["group_PDSPmvukpYgZEDXsoNirw3CFhy"] }'Response:
{ "mode": "limited", "groups": [ { "id": "group_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Platform Engineering" } ]}Get Grok Bot Network Policy
/grok-bot/networkReturn the team's Grok Bot network policy.
Response Fields
egressMode string
unset, allow_all, default_with_network_settings, or network_settings_only.allowlist array
host-or-CIDR:port such as 54.85.223.0/24:3306.locked boolean
true, group policies cannot override the team policy.curl -X GET https://api.cursor.com/grok-bot/network \ -u YOUR_API_KEY:Response:
{ "egressMode": "network_settings_only", "allowlist": ["linkedin.com", "*.crunchbase.com", "10.0.0.0/8", "54.85.223.0/24:3306"], "locked": true}Replace Grok Bot Network Policy
/grok-bot/networkReplace the team's Grok Bot network policy. Returns 403 on Teams plans.
Parameters
egressMode string Required
unset: Apply no policyallow_all: Allow every destinationdefault_with_network_settings: Cursor defaults plus the allowlistnetwork_settings_only: The allowlist and destinations required to run Grok Bot
allowlist array Required
host-or-CIDR:port such as 54.85.223.0/24:3306.locked boolean Required
true, group policies cannot override the team policy.Partial bodies, unknown modes, and invalid allowlist entries return 400.
curl -X PUT https://api.cursor.com/grok-bot/network \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "egressMode": "network_settings_only", "allowlist": ["linkedin.com", "*.crunchbase.com", "10.0.0.0/8", "54.85.223.0/24:3306"], "locked": true }'Response:
{ "egressMode": "network_settings_only", "allowlist": ["linkedin.com", "*.crunchbase.com", "10.0.0.0/8", "54.85.223.0/24:3306"], "locked": true}List Grok Bot Team Rules
/grok-bot/team-rulesList Grok Bot team rules, newest first.
Parameters
limit number
50. Maximum: 100.cursor string
nextCursor.curl -X GET "https://api.cursor.com/grok-bot/team-rules?limit=50" \ -u YOUR_API_KEY:Response:
{ "teamRules": [ { "id": "rule_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Ask before publishing", "content": "Never publish a release without an explicit go from the requester.", "enabled": true, "scope": "grokBot", "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:00.000Z" } ], "nextCursor": null}Create Grok Bot Team Rule
/grok-bot/team-rulesCreate a Grok Bot team rule. A team can store up to 50 Grok Bot rules. Returns 201.
Parameters
name string Required
content string Required
enabled boolean Required
curl -X POST https://api.cursor.com/grok-bot/team-rules \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "name": "Ask before publishing", "content": "Never publish a release without an explicit go from the requester.", "enabled": true }'Response:
{ "teamRule": { "id": "rule_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Ask before publishing", "content": "Never publish a release without an explicit go from the requester.", "enabled": true, "scope": "grokBot", "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:00.000Z" }}Update Grok Bot Team Rule
/grok-bot/team-rules/:idUpdate a Grok Bot team rule. Returns 404 when the rule does not exist.
Send at least one field.
Parameters
id string Required
name string
content string
enabled boolean
curl -X PATCH https://api.cursor.com/grok-bot/team-rules/rule_PDSPmvukpYgZEDXsoNirw3CFhy \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "enabled": false }'Response:
{ "teamRule": { "id": "rule_PDSPmvukpYgZEDXsoNirw3CFhy", "name": "Ask before publishing", "content": "Never publish a release without an explicit go from the requester.", "enabled": false, "scope": "grokBot", "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:00.000Z" }}Delete Grok Bot Team Rule
/grok-bot/team-rules/:idDelete a Grok Bot team rule. Returns 204 No Content on success.
Parameters
id string Required
curl -X DELETE https://api.cursor.com/grok-bot/team-rules/rule_PDSPmvukpYgZEDXsoNirw3CFhy \ -u YOUR_API_KEY:Response:
204 No ContentList Grok Bot Setup Manifests
/grok-bot/setup-manifestsList Grok Bot setup manifests, ordered by id.
Parameters
limit number
50. Maximum: 100.cursor string
nextCursor.curl -X GET "https://api.cursor.com/grok-bot/setup-manifests?limit=50" \ -u YOUR_API_KEY:Response:
{ "manifests": [ { "id": "toolchain", "scripts": [ { "id": "node", "setup": "mise install node@22", "check": "node --version" }, { "id": "pnpm", "setup": "npm i -g pnpm" } ] } ], "nextCursor": null}Upsert Grok Bot Setup Manifest
/grok-bot/setup-manifests/:manifestIdCreate or replace a setup manifest. A team can store up to 100 manifests. Returns 409 when the manifest changed during the request.
Parameters
manifestId string Required
., _, or -.scripts array Required
idstring: Same format asmanifestIdsetupstring: Non-empty install commandcheckstring: Optional verification command
curl -X PUT https://api.cursor.com/grok-bot/setup-manifests/toolchain \ -u YOUR_API_KEY: \ -H "Content-Type: application/json" \ -d '{ "scripts": [ { "id": "node", "setup": "mise install node@22", "check": "node --version" }, { "id": "pnpm", "setup": "npm i -g pnpm" } ] }'Response:
{ "manifest": { "id": "toolchain", "scripts": [ { "id": "node", "setup": "mise install node@22", "check": "node --version" }, { "id": "pnpm", "setup": "npm i -g pnpm" } ] }}Delete Grok Bot Setup Manifest
/grok-bot/setup-manifests/:manifestIdDelete a setup manifest. Returns 204 No Content on success.
Parameters
manifestId string Required
curl -X DELETE https://api.cursor.com/grok-bot/setup-manifests/toolchain \ -u YOUR_API_KEY:Response:
204 No ContentErrors
Error bodies use:
{ "code": "error", "message": "…" }| Status | When |
|---|---|
401 | Bad key, missing read:* / admin:*, or Grok Bot Admin API not enabled for the team |
403 | The write is not available to the team or its plan |
404 | A well-formed rule or manifest ID in the path does not exist |
409 | A setup manifest changed during the request |
400 | Invalid body or ID; empty PATCH; enabled on capabilities; unknown group; too many rules or manifests; no owner to attribute a setup manifest |
429 | The endpoint's rate limit was exceeded |