Admin API
The Admin API lets you programmatically access your team's data, including member information, usage metrics, spending details, and model access.
- 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_updatesearch 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:
{ "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", "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", "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 Balance or Auto Intelligence routes to a third-party model. Auto Cost, first-party Cursor models such as Composer 2.5 and Grok 4.5, and request-based enterprise accounts do not include this fee.
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 self-hosted pool worker or a personal "My Machine" worker)SELF_HOSTED_POOL- team self-hosted 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 Auto Balance or Auto Intelligence 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.
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"}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 indexed or 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 ContentBilling 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.
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, and per-provider / per-model toggles.
These routes return the team baseline. Organization Groups can still widen access for some members; group allowlists are not part of this API. Effort, reasoning, and 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) with the
admin:*scope. - 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 writes return 409 while
stateisunrestricted(orlegacy). The firstPUT /teams/model-access/configurationon an unrestricted team turns policy on and seeds the current catalog (same idea as the first save on the Models page). Later configuration PUTs update defaults only and leave existing toggles in place. - Clearing policy: There is no API to clear a team back to unrestricted. Use the dashboard if you need that.
- 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/configurationSet defaults for new providers and models. The first call on an unrestricted team creates a custom policy and seeds catalog entries. Later calls update defaults only and leave existing toggles in place.
Request body
newProviderDefault string Required
enabled or disabled.newModelDefault string Required
enabled or disabled.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"}List Model Access Providers
/teams/model-access/providersList catalog providers and models with resolved enabled flags. When state is not custom, providers is an empty array.
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-sonnet-4-6", "displayName": "Sonnet 4.6", "enabled": true }, { "id": "claude-opus-4-6", "displayName": "Opus 4.6", "enabled": false } ] }, { "id": "openai", "displayName": "OpenAI", "enabled": true, "models": [ { "id": "gpt-5.4", "displayName": "GPT-5.4", "enabled": true } ] } ]}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. 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. 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
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": false}'Response:
{ "id": "claude-opus-4-6", "displayName": "Opus 4.6", "enabled": false, "provider": "anthropic"}Errors
Error bodies use:
{ "code": "error", "message": "…" }| Status | When |
|---|---|
401 | Bad key, or missing admin:* |
403 | Model access control is not available for that team |
409 | Provider or model write while state is unrestricted or legacy |
400 | Unknown provider or model id, invalid body, or a Smart Auto required model would be blocked |