Cloud Agents API
The Cloud Agents API v1 is in public beta. APIs may change before general availability.
The Cloud Agents API lets you programmatically launch and manage cloud agents that work on your repositories.
- The Cloud Agents API accepts both Basic and Bearer authentication. Generate a user API key from Cursor Dashboard → API Keys, or use a service account API key.
- For details on authentication methods, rate limits, and best practices, see the API Overview.
- View the full OpenAPI specification for detailed schemas and examples.
- Webhooks are coming soon. The legacy v0 API still supports them — see Webhooks.
This API splits work into a durable agent plus per-prompt runs, replacing the flatter v0 surface. The legacy v0 reference remains available.
Endpoints
Create An Agent
/v1/agentsCreate a Cloud Agent and immediately enqueue its initial run. The response returns both the durable agent and the initial run.
Request Body
prompt object (required)
prompt.text string (required)
prompt.images array (optional)
data (base64-encoded bytes with a required mimeType) or url (an http or https URL that Cursor fetches). Maximum 5 images, 15 MB each. Supported MIME types: image/png, image/jpeg, image/gif, image/webp.model object (optional)
model.id string (required if model provided)
GET /v1/models (for example, claude-4-sonnet-thinking).model.params array (optional)
id and value. Use only parameters supported by the selected model — call GET /v1/models to discover the valid id/params combinations.name string (optional)
env object (optional)
cloud environment, or route to a self-hosted pool or machine. Mutually exclusive with explicit repos when selecting a named Cursor-hosted environment.env.type string (required if env provided)
cloud uses Cursor-hosted VMs; pool and machine route to self-hosted workers.env.name string (optional)
repos array (optional)
repos and env to start a no-repo agent. Maximum 20 repositories.repos[0].url string (required)
https://github.com/your-org/your-repo). Required on every repo entry, including when prUrl is provided.repos[0].startingRef string (optional)
prUrl is provided.repos[0].prUrl string (optional)
startingRef is ignored. url must still be set on the same repos entry.workOnCurrentBranch boolean (optional, default: false)
false (the default), Cursor pushes commits to a new auto-generated branch (cursor/...) based on repos[0].startingRef (or the PR base ref when prUrl is set). When true, Cursor pushes directly to that starting ref — for a non-PR create, that's the branch you passed in startingRef; for a prUrl create, that's the PR's head branch. The branch the agent pushed shows up in the agent's git.branches[].autoCreatePR boolean (optional)
skipReviewerRequest boolean (optional)
autoCreatePR is true.envVars object (optional)
CURSOR_), values up to 4096 bytes. Cannot be combined with a client-supplied agentId.envVars is rolling out. If it isn't enabled for your account yet, the field is silently ignored on create rather than failing the request — verify the values are present by inspecting the agent shell on a first run before relying on them in production.mcpServers array (optional)
headers or OAuth auth; stdio servers run inside the cloud VM and can receive env. Server names must be unique.mcpServers[0].name string (required)
mcpServers[0].type string (optional)
http, sse, or stdio. Defaults to http for remote servers with url, and stdio for servers with command.mcpServers[0].url string (required for remote MCP)
mcpServers[0].command string (required for stdio MCP)
args and env for arguments and runtime secrets.customSubagents array (optional)
name, description, and prompt, plus an optional model (model ID string, ModelSelection object, or "inherit"). Names must be unique and cannot collide with built-ins (explore, debug, shell, computerUse, etc.).mode string (optional, default: agent)
plan explores and drafts a plan before coding (Plan mode); agent implements changes directly.agentId string (optional)
bc-<uuid>. Useful for idempotent create flows — re-POSTing the same agentId returns 409 agent_id_conflict rather than creating a duplicate. Cannot be combined with envVars; omit agentId so the server mints one when you need session secrets.curl --request POST \ --url https://api.cursor.com/v1/agents \ -u YOUR_API_KEY: \ --header 'Content-Type: application/json' \ --data '{ "prompt": { "text": "Add a README with setup instructions" }, "model": { "id": "composer-2", "params": [ { "id": "fast", "value": "true" } ] }, "repos": [ { "url": "https://github.com/your-org/your-repo", "startingRef": "main" } ], "mcpServers": [ { "name": "linear", "type": "http", "url": "https://mcp.linear.app/sse", "headers": { "Authorization": "Bearer YOUR_LINEAR_API_KEY" } }, { "name": "github", "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_TOKEN": "YOUR_GITHUB_TOKEN" } } ], "autoCreatePR": true }'Response:
{ "agent": { "id": "bc-00000000-0000-0000-0000-000000000001", "name": "Add README with setup instructions", "status": "ACTIVE", "env": { "type": "cloud" }, "repos": [ { "url": "https://github.com/your-org/your-repo", "startingRef": "main" } ], "workOnCurrentBranch": false, "autoCreatePR": true, "url": "https://cursor.com/agents/bc-00000000-0000-0000-0000-000000000001", "createdAt": "2026-04-13T18:30:00.000Z", "updatedAt": "2026-04-13T18:30:00.000Z", "latestRunId": "run-00000000-0000-0000-0000-000000000001" }, "run": { "id": "run-00000000-0000-0000-0000-000000000001", "agentId": "bc-00000000-0000-0000-0000-000000000001", "status": "CREATING", "createdAt": "2026-04-13T18:30:00.000Z", "updatedAt": "2026-04-13T18:30:00.000Z" }}List Agents
/v1/agentsList agents for the authenticated user, newest first.
Query Parameters
limit number (optional)
cursor string (optional)
nextCursor on the previous response.prUrl string (optional)
includeArchived boolean (optional, default: true)
List items only include the durable identity fields. Call GET /v1/agents/{id} to load the full record (repos, workOnCurrentBranch, autoCreatePR, etc.).
nextCursor is omitted from the response when there are no more pages — it is not returned as null. Treat its absence as "no more results".
curl --request GET \ --url 'https://api.cursor.com/v1/agents?limit=20' \ -u YOUR_API_KEY:Response:
{ "items": [ { "id": "bc-00000000-0000-0000-0000-000000000001", "name": "Add README with setup instructions", "status": "ACTIVE", "env": { "type": "cloud" }, "url": "https://cursor.com/agents/bc-00000000-0000-0000-0000-000000000001", "createdAt": "2026-04-13T18:30:00.000Z", "updatedAt": "2026-04-13T18:45:00.000Z", "latestRunId": "run-00000000-0000-0000-0000-000000000001" } ], "nextCursor": "bc-00000000-0000-0000-0000-000000000002"}Get An Agent
/v1/agents/{id}Retrieve durable metadata for an agent. Execution status lives on runs — fetch latestRunId and call Get A Run to read run state.
Path Parameters
id string
bc-00000000-0000-0000-0000-000000000001).curl --request GET \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001 \ -u YOUR_API_KEY:Response:
{ "id": "bc-00000000-0000-0000-0000-000000000001", "name": "Add README with setup instructions", "status": "ACTIVE", "env": { "type": "cloud" }, "repos": [ { "url": "https://github.com/your-org/your-repo", "startingRef": "main" } ], "workOnCurrentBranch": false, "autoCreatePR": true, "url": "https://cursor.com/agents/bc-00000000-0000-0000-0000-000000000001", "createdAt": "2026-04-13T18:30:00.000Z", "updatedAt": "2026-04-13T18:30:00.000Z", "latestRunId": "run-00000000-0000-0000-0000-000000000001"}Create A Run
/v1/agents/{id}/runsSend a follow-up prompt to an existing active agent. The new run uses the agent's current conversation and workspace state.
Only one run can be active per agent. Calling this while another run is CREATING or RUNNING returns 409 agent_busy. Wait for the existing run to terminate, or cancel it.
Path Parameters
id string
bc-00000000-0000-0000-0000-000000000001).Request Body
prompt object (required)
prompt.text string (required)
prompt.images array (optional)
data (base64-encoded bytes with a required mimeType) or url. Maximum 5 images, 15 MB each. Supported MIME types: image/png, image/jpeg, image/gif, image/webp.mcpServers array (optional)
mode string (optional)
agent or plan. Omit to keep the conversation's current mode from prior runs.curl --request POST \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/runs \ -u YOUR_API_KEY: \ --header 'Content-Type: application/json' \ --data '{ "prompt": { "text": "Also add troubleshooting steps" }, "mcpServers": [ { "name": "docs", "type": "http", "url": "https://example.com/mcp" } ] }'Response:
{ "run": { "id": "run-00000000-0000-0000-0000-000000000002", "agentId": "bc-00000000-0000-0000-0000-000000000001", "status": "CREATING", "createdAt": "2026-04-13T18:50:00.000Z", "updatedAt": "2026-04-13T18:50:00.000Z" }}List Runs
/v1/agents/{id}/runsList runs for an agent, newest first.
Path Parameters
id string
Query Parameters
limit number (optional)
cursor string (optional)
nextCursor on the previous response.curl --request GET \ --url 'https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/runs?limit=20' \ -u YOUR_API_KEY:Response:
{ "items": [ { "id": "run-00000000-0000-0000-0000-000000000002", "agentId": "bc-00000000-0000-0000-0000-000000000001", "status": "RUNNING", "createdAt": "2026-04-13T18:50:00.000Z", "updatedAt": "2026-04-13T18:51:00.000Z", "git": { "branches": [ { "repoUrl": "github.com/your-org/your-repo", "branch": "cursor/add-readme-a1b2" } ] } } ]}Get A Run
/v1/agents/{id}/runs/{runId}Retrieve status, timestamps, and (for terminal runs) the final result, duration, and pushed branches for a specific run.
Path Parameters
id string
runId string
run-00000000-0000-0000-0000-000000000001).Response Fields
The base run fields (id, agentId, status, createdAt, updatedAt) are always present. The following are populated as soon as data is available:
durationMs integer (terminal runs)
FINISHED, ERROR, CANCELLED, or EXPIRED.result string (terminal runs)
git object (when a branch has been pushed)
git.branches[] contains { repoUrl, branch?, prUrl? } entries — one per branch the agent has pushed (stacked agents produce multiple).git snapshot. Use the agent's latestRunId or the SSE stream to attribute work to a specific run.repoUrl is returned without the scheme (for example, github.com/your-org/your-repo) — different from request repos[].url, which keeps the https:// prefix.curl --request GET \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/runs/run-00000000-0000-0000-0000-000000000001 \ -u YOUR_API_KEY:Response:
{ "id": "run-00000000-0000-0000-0000-000000000001", "agentId": "bc-00000000-0000-0000-0000-000000000001", "status": "FINISHED", "createdAt": "2026-04-13T18:30:00.000Z", "updatedAt": "2026-04-13T18:45:00.000Z", "durationMs": 12357, "result": "Added README.md with installation instructions and usage examples.", "git": { "branches": [ { "repoUrl": "github.com/your-org/your-repo", "branch": "cursor/add-readme-a1b2", "prUrl": "https://github.com/your-org/your-repo/pull/123" } ] }}Stream A Run
/v1/agents/{id}/runs/{runId}/streamStream Server-Sent Events (SSE) for one run. The stream is scoped to the requested run and does not replay prior runs.
Event types
status— run status update. Payload:{ runId, status }.assistant— assistant text delta. Payload:{ text }.thinking— thinking text delta. Payload:{ text }.tool_call— tool call status update. Payload:{ callId, name, status, args?, result?, truncated? }.interaction_update— optional richer event emitted alongside the simplified events above. Payload matches theInteractionUpdateshape consumed by the TypeScript SDK, with subtypes liketext-delta,tool-call-started/tool-call-completed,step-started/step-completed, andturn-ended. If you only need plain text and tool calls, handle the simplified events and ignoreinteraction_update. If you want the full SDK-shape stream, handleinteraction_updateand ignore the simplified events.heartbeat— keepalive event. Payload:{}.result— terminal run status. Payload:{ runId, status, text?, durationMs?, git? }.textis the final assistant reply,durationMsis the wall-clock run duration in milliseconds, andgitmirrorsRun.git(the agent's current pushed branches, not just this run's).error— stream error. Payload:{ code, message }.done— stream complete. Payload:{}.
Tool call payloads
tool_call events use a stable envelope around tool-specific inputs and outputs:
type JsonValue = | string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };interface ToolCallEventData { callId: string; name: string; status: "running" | "completed"; args?: JsonValue; result?: JsonValue; truncated?: { args?: true; result?: true; };}callId identifies one tool invocation across updates. name is the public tool name, such as read_file, run_terminal_cmd, or mcp. args and result are tool-specific JSON values. If args or result is too large to include in the stream, Cursor omits that field and sets the matching truncated flag.
Resuming a stream
Most events include an id line — an opaque string you should not parse (current format looks like 1713033006000-0, but treat it as opaque). The leading status event has no id — it is a sticky framing event that is re-sent at the top of every reconnect.
To resume after a disconnect, reconnect with Last-Event-ID set to the most recent received event id. The event id must belong to the requested run; otherwise the request returns 400 invalid_last_event_id. After a successful resume, expect another status event before the resumed range begins.
Retention
Stream responses include the X-Cursor-Stream-Retention-Seconds header. After the retention window elapses, this endpoint may return 410 stream_expired. Treat that as a signal to read terminal state via Get A Run instead of retrying the stream.
curl --request GET \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/runs/run-00000000-0000-0000-0000-000000000001/stream \ -u YOUR_API_KEY: \ --header 'Accept: text/event-stream'Example stream:
event: statusdata: {"runId":"run-00000000-0000-0000-0000-000000000001","status":"RUNNING"}id: 1713033000000-0event: assistantdata: {"text":"I'll update the README now."}id: 1713033005000-0event: tool_calldata: {"callId":"call-1","name":"read_file","status":"running","args":{"path":"README.md"}}id: 1713033006000-0event: tool_calldata: {"callId":"call-1","name":"read_file","status":"completed","args":{"path":"README.md"},"result":{"success":{"content":"# Project","totalLines":1,"fileSize":9,"path":"README.md"}}}id: 1713033010000-0event: resultdata: {"runId":"run-00000000-0000-0000-0000-000000000001","status":"FINISHED","text":"Added README.md with installation instructions.","durationMs":12357,"git":{"branches":[{"repoUrl":"github.com/your-org/your-repo","branch":"cursor/add-readme-a1b2"}]}}id: 1713033010000-0event: donedata: {}Cancel A Run
/v1/agents/{id}/runs/{runId}/cancelCancel the active run for an agent. Cancellation is terminal — the run transitions to CANCELLED and cannot be resumed. To continue the conversation, create a new run on the same agent.
Cancelling a run that is already in a terminal state, or one that was never active, returns 409 run_not_cancellable.
Path Parameters
id string
runId string
curl --request POST \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/runs/run-00000000-0000-0000-0000-000000000001/cancel \ -u YOUR_API_KEY:Response:
{ "id": "run-00000000-0000-0000-0000-000000000001"}Get Agent Usage
/v1/agents/{id}/usageRetrieve token usage for an agent, broken down per run. The response totals usage across every run on the agent and lists usage for each individual run. Token usage matches the tokenUsage reported by the team usage events endpoint.
Path Parameters
id string
bc-00000000-0000-0000-0000-000000000001).Query Parameters
runId string (optional)
run-00000000-0000-0000-0000-000000000001). Omit to return usage for every run on the agent. An unknown runId returns 404 run_not_found.Response Fields
totalUsage object
usage object.runs array
runId is set). Each object contains:idstring - Run identifier (for example,run-00000000-0000-0000-0000-000000000001).usageUuidstring (optional) - Internal usage identifier for the run. Omitted when the run has no recorded usage yet.usageobject - Token usage for this run:inputTokensnumber - Input tokens consumed.outputTokensnumber - Output tokens generated.cacheWriteTokensnumber - Tokens written to cache.cacheReadTokensnumber - Tokens read from cache.totalTokensnumber - Sum of the four token counts above.
Runs without any recorded token usage report zeros across all fields. A run that hasn't produced usage yet still appears in runs so you can track it over time.
# All runs on the agentcurl --request GET \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/usage \ -u YOUR_API_KEY:# A single runcurl --request GET \ --url 'https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/usage?runId=run-00000000-0000-0000-0000-000000000001' \ -u YOUR_API_KEY:Response:
{ "totalUsage": { "inputTokens": 12480, "outputTokens": 3110, "cacheWriteTokens": 18200, "cacheReadTokens": 42600, "totalTokens": 76390 }, "runs": [ { "id": "run-00000000-0000-0000-0000-000000000002", "usageUuid": "00000000-0000-0000-0000-000000000002", "usage": { "inputTokens": 6320, "outputTokens": 1450, "cacheWriteTokens": 7100, "cacheReadTokens": 21300, "totalTokens": 36170 } }, { "id": "run-00000000-0000-0000-0000-000000000001", "usageUuid": "00000000-0000-0000-0000-000000000001", "usage": { "inputTokens": 6160, "outputTokens": 1660, "cacheWriteTokens": 11100, "cacheReadTokens": 21300, "totalTokens": 40220 } } ]}Artifacts
Artifacts are agent-scoped because the workspace persists across runs.
List Artifacts
/v1/agents/{id}/artifactsList artifacts produced by an agent. Each artifact's path is relative to the workspace's artifacts/ directory.
Pass the path value returned here directly to Download An Artifact. v1 paths are relative; absolute v0 paths (/opt/cursor/artifacts/...) are not accepted.
Path Parameters
id string
curl --request GET \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/artifacts \ -u YOUR_API_KEY:Response:
{ "items": [ { "path": "artifacts/screenshot.png", "sizeBytes": 12345, "updatedAt": "2026-04-13T18:45:00.000Z" } ]}Download An Artifact
/v1/agents/{id}/artifacts/downloadRetrieve a temporary 15-minute presigned S3 URL for a specific artifact.
Path Parameters
id string
Query Parameters
path string
artifacts/screenshot.png). Must be under artifacts/.curl --request GET \ --url 'https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/artifacts/download?path=artifacts/screenshot.png' \ -u YOUR_API_KEY:Response:
{ "url": "https://cloud-agent-artifacts.s3.us-east-1.amazonaws.com/...", "expiresAt": "2026-04-13T19:00:00.000Z"}Agent Lifecycle
Archive An Agent
/v1/agents/{id}/archiveArchive an agent. Archived agents remain readable but cannot accept new runs until unarchived. Use this for reversible "soft delete" flows.
Archive is idempotent — re-archiving an already-archived agent returns 200 with no change. You don't need to check current state before calling.
Path Parameters
id string
curl --request POST \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/archive \ -u YOUR_API_KEY:Response:
{ "id": "bc-00000000-0000-0000-0000-000000000001"}Unarchive An Agent
/v1/agents/{id}/unarchiveUnarchive an agent so it can accept new runs again.
Unarchive is idempotent — calling it on an already-active agent returns 200 with no change.
Path Parameters
id string
curl --request POST \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001/unarchive \ -u YOUR_API_KEY:Response:
{ "id": "bc-00000000-0000-0000-0000-000000000001"}Delete An Agent Permanently
/v1/agents/{id}Permanently delete an agent. This action is irreversible. Use Archive for reversible removal.
Path Parameters
id string
curl --request DELETE \ --url https://api.cursor.com/v1/agents/bc-00000000-0000-0000-0000-000000000001 \ -u YOUR_API_KEY:Response:
{ "id": "bc-00000000-0000-0000-0000-000000000001"}Worker Tokens
Create A User-Scoped Worker Token
/v1/sub-tokensCreate a one-hour user-scoped token for a self-hosted worker to run as an active team member.
Requires an agent-scoped team service account API key. User-scoped tokens can't mint other user-scoped tokens.
The returned token expires after 1 hour and cannot refresh itself. Mint a new token with the service account API key when you need to refresh a running worker.
Request Body
Specify exactly one of the following to identify the target user:
forUserEmail string (optional)
forUserId integer (optional)
By email:
curl --request POST \ --url https://api.cursor.com/v1/sub-tokens \ --header "Authorization: Bearer $CURSOR_SERVICE_ACCOUNT_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "forUserEmail": "alice@company.com" }'By user ID:
curl --request POST \ --url https://api.cursor.com/v1/sub-tokens \ --header "Authorization: Bearer $CURSOR_SERVICE_ACCOUNT_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "forUserId": 42 }'Response:
{ "accessToken": "eyJ...", "expiresAt": "2026-04-24T19:00:00.000Z", "userId": 42, "teamId": 456}Fleet Management
Monitor pool worker utilization and build autoscaling against self-hosted Cloud Agent pools.
Authenticate with the pool's service account API key via Basic auth or Bearer token. Other API key types are rejected.
List Workers
/v0/private-workersList self-hosted pool workers for the authenticated service account's team, newest first.
Query Parameters
status string (optional, default: all)
all, in_use, or idle.limit integer (optional, default: 50)
nextPageToken string (optional)
curl --request GET \ --url "https://api.cursor.com/v0/private-workers?status=idle&limit=50" \ -u "$CURSOR_API_KEY:"Get Fleet Summary
/v0/private-workers/summaryReturn connected and in-use worker counts for the authenticated user and their team. Use this to trigger scaling decisions when utilization is high.
curl --request GET \ --url "https://api.cursor.com/v0/private-workers/summary" \ -u "$CURSOR_API_KEY:"Example scaling check:
const summary = await response.json();const team = summary.teamSummary;if (team && team.totalConnected > 0) { const utilization = team.inUse / team.totalConnected; if (utilization >= 0.9) { // Scale up: provision additional workers }}Get Worker By ID
/v0/private-workers/{id}Retrieve a single self-hosted pool worker by its ID.
Path Parameters
id string
pw_123).curl --request GET \ --url "https://api.cursor.com/v0/private-workers/pw_123" \ -u "$CURSOR_API_KEY:"List Pending Pool Requests
/v0/private-workers/pending-requestsList self-hosted pool requests that have not been assigned to a worker yet. Use this endpoint to scale capacity when users are waiting for an available pool worker.
This endpoint requires a service account API key. It returns requests for the key's team and excludes My Machines requests. If the key is scoped to specific repositories, pass repository; the repository must be in the key's allowed scope.
Query Parameters
limit number (optional)
pageToken string (optional)
repository string (optional)
curl --request GET \ --url "https://api.cursor.com/v0/private-workers/pending-requests?limit=50&repository=https%3A%2F%2Fgithub.com%2Facme%2Fpayments-service" \ -u "$CURSOR_API_KEY:"Response:
{ "requests": [ { "id": "bc-00000000-0000-0000-0000-000000000002", "userId": 321, "serviceAccountId": "sa_abc123", "repoOwner": "acme", "repoName": "payments-service", "repoUrl": "https://github.com/acme/payments-service", "labels": [ { "key": "repo", "value": "acme/payments-service" }, { "key": "pool", "value": "gpu" }, { "key": "env", "value": "production" } ], "createdAtMs": 1737306880000 } ], "nextPageToken": "eyJjcmVhdGVkQXRNcyI6MTczNzMwNjg4MDAwMH0="}repoUrl omits embedded credentials when the original repository URL includes userinfo.
Metadata Endpoints
API Key Info
/v1/meRetrieve information about the API key being used for authentication.
Response Fields
apiKeyName string
createdAt string
userId integer (user-scoped keys)
userEmail string (user-scoped keys)
userFirstName, userLastName string (user-scoped keys)
curl --request GET \ --url https://api.cursor.com/v1/me \ -u YOUR_API_KEY:Response (user-scoped key):
{ "apiKeyName": "Production API Key", "userId": 42, "createdAt": "2026-04-13T18:30:00.000Z", "userEmail": "developer@example.com", "userFirstName": "Alex", "userLastName": "Rivera"}Response (service-account key):
{ "apiKeyName": "Production Service Account", "createdAt": "2026-04-13T18:30:00.000Z"}List Models
/v1/modelsReturns the recommended models you can pass to the model.id field on Create An Agent, along with the parameters and variants each model accepts. Model parameters use the same model.params shape as the TypeScript SDK ModelSelection.
To use the configured default model, omit model from the request body entirely. Cursor resolves your user default model, then your team default model, then a system default.
Response Fields
Each item in items describes one model:
id string
model.id when creating an agent.displayName string
description string (optional)
aliases array (optional)
composer-latest).parameters array (optional)
id, optional displayName, and a values array of permitted { value, displayName? } entries. Use these to populate model.params on the create request.variants array (optional)
id+params combinations the model accepts. Each entry has a params array (which may be empty), a displayName, an optional description, and an optional isDefault flag.curl --request GET \ --url https://api.cursor.com/v1/models \ -u YOUR_API_KEY:Response:
{ "items": [ { "id": "composer-2", "displayName": "Composer 2", "aliases": ["composer-latest", "composer"], "parameters": [ { "id": "fast", "displayName": "Fast", "values": [ { "value": "false" }, { "value": "true", "displayName": "Fast" } ] } ], "variants": [ { "params": [{ "id": "fast", "value": "true" }], "displayName": "Composer 2", "isDefault": true }, { "params": [{ "id": "fast", "value": "false" }], "displayName": "Composer 2" } ] }, { "id": "claude-4.6-sonnet-thinking", "displayName": "Claude 4.6 Sonnet (Thinking)", "variants": [ { "params": [], "displayName": "Claude 4.6 Sonnet (Thinking)", "isDefault": true } ] } ]}List GitHub Repositories
/v1/repositoriesList GitHub repositories accessible to the authenticated user through Cursor's GitHub App installation.
This endpoint has very strict rate limits.
Limit requests to 1 / user / minute, and 30 / user / hour.
This request can take tens of seconds to respond for users with access to many repositories.
Make sure to handle this information not being available gracefully.
curl --request GET \ --url https://api.cursor.com/v1/repositories \ -u YOUR_API_KEY:Response:
{ "items": [ { "url": "https://github.com/your-org/your-repo" } ]}