openapi: 3.0.3
info:
  title: Cursor Cloud Agents API
  description: |
    Programmatically create and manage Cursor Cloud Agents that work
    autonomously on your repositories. v1 separates a durable agent
    from one or more runs: each prompt submission creates a run on the
    agent. Streaming and cancellation are scoped to the active run.
    Environment endpoints manage the saved environments agents run in.
  version: 1.0.0
  contact:
    email: hi@cursor.com

servers:
  - url: https://api.cursor.com
    description: Production server

security:
  - basicAuth: []
  - bearerAuth: []

components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: |
        API key from Cursor Dashboard, supplied as the Basic
        Authentication username with an empty password.
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        API key from Cursor Dashboard, supplied via
        `Authorization: Bearer <key>`. Equivalent to Basic Auth.

  schemas:
    ImageDimension:
      type: object
      required:
        - width
        - height
      properties:
        width:
          type: integer
          minimum: 1
          description: Width in pixels
        height:
          type: integer
          minimum: 1
          description: Height in pixels

    Image:
      type: object
      description: |
        An image input. Provide exactly one of `data` or `url`. When
        `data` is provided, `mimeType` is required. When `url` is
        provided, Cursor fetches the image and `mimeType` must be
        omitted.
      properties:
        data:
          type: string
          minLength: 1
          description: Base64 encoded image bytes (max 15 MB). Mutually exclusive with `url`.
          example: 'iVBORw0KGgoAAAANSUhEUgAA...'
        url:
          type: string
          format: uri
          description: HTTP or HTTPS URL Cursor fetches. Mutually exclusive with `data`.
          example: 'https://example.com/screenshot.png'
        mimeType:
          type: string
          minLength: 1
          description: MIME type of the image bytes. Required when `data` is provided; must be omitted when `url` is provided. Supported types are `image/png`, `image/jpeg`, `image/gif`, and `image/webp`.
          example: 'image/png'
        dimension:
          $ref: '#/components/schemas/ImageDimension'
      oneOf:
        - required: [data, mimeType]
          not:
            required: [url]
        - required: [url]
          not:
            anyOf:
              - required: [data]
              - required: [mimeType]

    ModelRef:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: Explicit model ID returned by GET /v1/models. Omit `model` from the request to use the configured default.
          example: 'composer-2'
        params:
          type: array
          description: Per-model parameters such as reasoning effort or max mode. Use only parameters supported by the selected model.
          items:
            type: object
            required:
              - id
              - value
            properties:
              id:
                type: string
                minLength: 1
                example: 'thinking'
              value:
                type: string
                minLength: 1
                example: 'high'

    RepoConfig:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          minLength: 1
          description: GitHub repository URL. Required on every repo entry, including when `prUrl` is provided.
          example: 'https://github.com/your-org/your-repo'
        startingRef:
          type: string
          minLength: 1
          description: Branch name or commit SHA to use as the starting point. Ignored when `prUrl` is provided.
          example: 'main'
        prUrl:
          type: string
          format: uri
          description: GitHub pull request URL. When provided, the agent works on this PR's repository and branches; `startingRef` is ignored. `url` must still be set on the same entry.
          example: 'https://github.com/your-org/your-repo/pull/123'

    AgentEnv:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum: ['cloud', 'pool', 'machine']
          description: Execution environment type. `cloud` uses Cursor-hosted VMs; `pool` and `machine` route to self-hosted workers.
          example: 'cloud'
        name:
          type: string
          minLength: 1
          description: 'Named Cursor-hosted environment, Team Pool, or self-hosted machine name. For `type: pool`, this is the pool name (defaults to `default` when omitted). Unknown pool names return `400`. Omit `repos` with `type: pool` to target a repo-less pool. Name an any-repo pool to send more than one entry in `repos`.'
          example: 'Release workspace'

    McpAuth:
      type: object
      additionalProperties: false
      required:
        - CLIENT_ID
      properties:
        CLIENT_ID:
          type: string
          minLength: 1
          description: OAuth client ID for the MCP server.
          example: 'client-id'
        CLIENT_SECRET:
          type: string
          description: OAuth client secret for the MCP server.
          example: 'client-secret'
        scopes:
          type: array
          description: OAuth scopes to request for the MCP server.
          items:
            type: string
            minLength: 1
          example: ['file_content:read']

    StdioMcpServer:
      type: object
      additionalProperties: false
      required:
        - name
        - command
      properties:
        name:
          type: string
          minLength: 1
          description: MCP server name exposed to the agent.
          example: 'github'
        type:
          type: string
          enum: ['stdio']
          description: Stdio MCP server. Defaults to `stdio` when `command` is provided.
          example: 'stdio'
        command:
          type: string
          minLength: 1
          description: Command to start inside the cloud agent VM.
          example: 'npx'
        args:
          type: array
          description: Command arguments.
          items:
            type: string
          example: ['-y', '@modelcontextprotocol/server-github']
        env:
          type: object
          description: Environment variables passed to the stdio MCP server inside the VM.
          additionalProperties:
            type: string
          example:
            GITHUB_TOKEN: 'ghp_...'

    RemoteMcpServer:
      type: object
      additionalProperties: false
      required:
        - name
        - url
      properties:
        name:
          type: string
          minLength: 1
          description: MCP server name exposed to the agent.
          example: 'linear'
        type:
          type: string
          enum: ['http', 'sse']
          description: Remote MCP transport. Defaults to `http` when `url` is provided.
          example: 'http'
        url:
          type: string
          format: uri
          description: HTTP or HTTPS URL for the remote MCP server. Userinfo in the URL is not allowed.
          example: 'https://mcp.linear.app/sse'
        headers:
          type: object
          description: Headers Cursor sends with every request to the remote MCP server.
          additionalProperties:
            type: string
          example:
            Authorization: 'Bearer lin_api_...'
        auth:
          $ref: '#/components/schemas/McpAuth'

    McpServer:
      oneOf:
        - $ref: '#/components/schemas/StdioMcpServer'
        - $ref: '#/components/schemas/RemoteMcpServer'

    AgentSummary:
      type: object
      required:
        - id
        - status
        - env
        - url
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          description: Unique agent identifier.
          example: 'bc-00000000-0000-0000-0000-000000000001'
        name:
          type: string
          description: Display name. Auto-derived from the prompt when not supplied at create time. Omitted when no name has been set.
          example: 'Add README with setup instructions'
        status:
          type: string
          enum: ['ACTIVE', 'ARCHIVED']
          description: Agent lifecycle state. Execution status lives on runs.
        env:
          $ref: '#/components/schemas/AgentEnv'
        url:
          type: string
          format: uri
          description: URL to view the agent in Cursor Web.
          example: 'https://cursor.com/agents/bc-00000000-0000-0000-0000-000000000001'
        createdAt:
          type: string
          format: date-time
          description: When the agent was created.
        updatedAt:
          type: string
          format: date-time
          description: When the agent was last updated.
        latestRunId:
          type: string
          description: ID of the most recent run on this agent, if any.
          example: 'run-00000000-0000-0000-0000-000000000001'

    Agent:
      allOf:
        - $ref: '#/components/schemas/AgentSummary'
        - type: object
          properties:
            repos:
              type: array
              description: Repository configuration. Empty for no-repo agents.
              items:
                $ref: '#/components/schemas/RepoConfig'
            workOnCurrentBranch:
              type: boolean
              description: When `false` (the default), Cursor pushes commits to a new auto-generated branch. When `true`, commits land on the existing head branch.
              example: false
            autoCreatePR:
              type: boolean
              description: Whether Cursor opens a pull request when the run completes.
              example: true
            skipReviewerRequest:
              type: boolean
              description: Whether to skip requesting the user as a reviewer when Cursor opens a PR.
            customSubagents:
              type: array
              description: Custom subagents defined at create time. Omitted when none were provided.
              items:
                $ref: '#/components/schemas/CustomSubagent'

    RunGitBranch:
      type: object
      required:
        - repoUrl
      properties:
        repoUrl:
          type: string
          minLength: 1
          description: Repository URL the agent pushed to. Returned without the scheme (for example, `github.com/your-org/your-repo`).
          example: 'github.com/your-org/your-repo'
        branch:
          type: string
          minLength: 1
          description: Branch name the agent pushed.
          example: 'cursor/add-readme-a1b2'
        prUrl:
          type: string
          format: uri
          description: Pull request URL, when Cursor opened a PR.
          example: 'https://github.com/your-org/your-repo/pull/123'

    RunGit:
      type: object
      description: |
        The agent's current pushed branches and pull requests. This is
        per-agent state — every run on the same agent returns the same
        `git` snapshot rather than only that run's contributions. Use
        the agent's `latestRunId` or the SSE stream to attribute work
        to a specific run.
      required:
        - branches
      properties:
        branches:
          type: array
          description: Branches the agent has pushed. Stacked agents return one entry per branch.
          items:
            $ref: '#/components/schemas/RunGitBranch'

    Run:
      type: object
      required:
        - id
        - agentId
        - status
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          description: Unique run identifier.
          example: 'run-00000000-0000-0000-0000-000000000001'
        agentId:
          type: string
          description: ID of the agent this run belongs to.
          example: 'bc-00000000-0000-0000-0000-000000000001'
        status:
          type: string
          enum:
            ['CREATING', 'RUNNING', 'WAITING_FOR_BACKGROUND_WORK', 'FINISHED', 'ERROR', 'CANCELLED', 'EXPIRED']
          description: Current run status. `CREATING`, `RUNNING`, and `WAITING_FOR_BACKGROUND_WORK` mean the run is active, and `FINISHED`, `ERROR`, `CANCELLED`, and `EXPIRED` mean it has ended.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        durationMs:
          type: integer
          minimum: 0
          description: Wall-clock duration of the run in milliseconds. Populated once the run reaches a terminal status (`FINISHED`, `ERROR`, `CANCELLED`, `EXPIRED`).
          example: 12357
        result:
          type: string
          minLength: 1
          description: Final assistant reply text. Populated once the run terminates.
          example: 'Added README.md with installation instructions.'
        git:
          allOf:
            - $ref: '#/components/schemas/RunGit'
          description: The agent's pushed branches and PRs. Populated once the agent has pushed at least one branch. Per-agent state, not per-run.

    RunStreamToolCallTruncation:
      type: object
      additionalProperties: false
      properties:
        args:
          type: boolean
          description: Present and true when the tool arguments were too large to include in the stream.
          example: true
        result:
          type: boolean
          description: Present and true when the tool result was too large to include in the stream.
          example: true

    JsonValue:
      description: Any JSON value.
      nullable: true
      oneOf:
        - type: string
        - type: number
        - type: boolean
        - type: object
          additionalProperties: true
        - type: array
          items: {}

    RunStreamToolCallData:
      type: object
      additionalProperties: false
      required:
        - callId
        - name
        - status
      properties:
        callId:
          type: string
          minLength: 1
          description: Stable identifier for one tool invocation across updates.
          example: 'call-1'
        name:
          type: string
          minLength: 1
          description: Public tool name, such as `read_file`, `run_terminal_cmd`, or `mcp`.
          example: 'read_file'
        status:
          type: string
          enum: ['running', 'completed']
          description: Tool invocation lifecycle status.
          example: 'completed'
        args:
          allOf:
            - $ref: '#/components/schemas/JsonValue'
          description: Tool-specific JSON arguments, when available.
          example:
            path: 'README.md'
        result:
          allOf:
            - $ref: '#/components/schemas/JsonValue'
          description: Tool-specific JSON result, when available.
          example:
            success:
              content: '# Project'
              totalLines: 1
              fileSize: 9
              path: 'README.md'
        truncated:
          $ref: '#/components/schemas/RunStreamToolCallTruncation'

    RunStreamToolCallEvent:
      type: object
      additionalProperties: false
      required:
        - event
        - data
      properties:
        event:
          type: string
          enum: ['tool_call']
        id:
          type: string
          description: Opaque SSE event id passed back via `Last-Event-ID` to resume the stream. Do not parse — the format is implementation-defined.
          example: '1713033006000-0'
        data:
          $ref: '#/components/schemas/RunStreamToolCallData'

    CustomSubagent:
      type: object
      additionalProperties: false
      required:
        - name
        - description
        - prompt
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Subagent name. Must be unique within `customSubagents` and cannot collide with built-ins (for example, `explore`, `shell`, `debug`, `computerUse`, `cursorGuide`).
          example: 'frontend-reviewer'
        description:
          type: string
          minLength: 1
          maxLength: 1000
          description: Short summary used by the main agent to decide when to delegate.
        prompt:
          type: string
          minLength: 1
          maxLength: 8192
          description: System prompt the subagent receives when invoked.
        model:
          oneOf:
            - type: string
              enum: ['inherit']
              description: Use the parent agent's model selection.
            - type: string
              minLength: 1
              description: An explicit model ID.
              example: 'claude-4.6-sonnet-thinking'
            - $ref: '#/components/schemas/ModelRef'

    CreateAgentRequest:
      type: object
      required:
        - prompt
      properties:
        prompt:
          type: object
          required:
            - text
          properties:
            text:
              type: string
              minLength: 1
              description: Task instruction for the agent.
              example: 'Add a README with setup instructions'
            images:
              type: array
              maxItems: 5
              items:
                $ref: '#/components/schemas/Image'
              description: Image inputs. Each entry must provide either `data` (with required `mimeType`) or `url`. Maximum 5 images, 15 MB each.
        model:
          $ref: '#/components/schemas/ModelRef'
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Display name for the agent. Auto-derived from the prompt when omitted.
          example: 'Add README with setup instructions'
        agentId:
          type: string
          minLength: 1
          pattern: '^bc-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
          description: Optional client-supplied agent identifier in `bc-<uuid>` form. Re-POSTing the same `agentId` returns `409 agent_id_conflict` instead of creating a duplicate. Cannot be combined with `envVars`; omit `agentId` so the server mints one when you need session secrets.
          example: 'bc-00000000-0000-0000-0000-000000000001'
        env:
          $ref: '#/components/schemas/AgentEnv'
        repos:
          type: array
          maxItems: 500
          description: 'Repository configuration. Mutually exclusive with a named cloud environment. Omit both `repos` and `env` (or pass `repos: []`) to start a no-repo agent. On self-hosted targets, only a named any-repo pool takes more than one entry. `machine`, the `default` pool, and repo-backed pools take one and return `400` for more.'
          items:
            $ref: '#/components/schemas/RepoConfig'
        workOnCurrentBranch:
          type: boolean
          description: |
            When `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.
          default: false
        autoCreatePR:
          type: boolean
          description: Whether Cursor should open a pull request when the run completes.
          default: false
        skipReviewerRequest:
          type: boolean
          description: Whether to skip requesting the user as a reviewer when Cursor opens a PR. Only applies when `autoCreatePR` is true.
          default: false
        envVars:
          allOf:
            - $ref: '#/components/schemas/EnvVars'
          description: |
            Session-scoped environment variables for the cloud agent.
            Values are encrypted at rest, injected into the agent's
            shell, and deleted with the agent. Names and values follow
            the `EnvVars` rules. Cannot be combined with a
            client-supplied `agentId`.

            Beta: `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 on a first run before relying on them in
            production.
        mcpServers:
          type: array
          maxItems: 50
          description: Inline MCP server definitions available to the initial run. Remote servers support `headers` or OAuth `auth`; stdio servers run inside the cloud agent VM and can receive `env`. Server names must be unique.
          items:
            $ref: '#/components/schemas/McpServer'
        customSubagents:
          type: array
          maxItems: 20
          description: Custom subagents the main agent can delegate to. Names must be unique and not collide with built-ins.
          items:
            $ref: '#/components/schemas/CustomSubagent'
        mode:
          allOf:
            - $ref: '#/components/schemas/AgentMode'
          default: agent
          description: Initial conversation mode for the agent's first run.

    EnvVars:
      type: object
      maxProperties: 50
      description: |
        Environment variables, at most 50. Each name is 1 to 255
        characters of ASCII letters, digits, and underscores, doesn't
        start with a digit, can't start with `CURSOR_`, and can't
        contain `CURSOR_SANDBOX` in any letter case. Each value is
        non-empty and at most 4096 UTF-8 bytes. `maxLength` counts
        characters, so it's only an upper bound on the byte limit.
      additionalProperties:
        type: string
        minLength: 1
        maxLength: 4096

    CreateRunRequest:
      description: |
        An ordinary follow-up, which omits `delivery`, or a steer, which
        sets `delivery` to `steer`.
      oneOf:
        - $ref: '#/components/schemas/FollowupRunRequest'
        - $ref: '#/components/schemas/SteerRunRequest'

    RunPrompt:
      type: object
      required:
        - text
      properties:
        text:
          type: string
          minLength: 1
          description: Follow-up instruction text.
          example: 'Also add troubleshooting steps'
        images:
          type: array
          maxItems: 5
          items:
            $ref: '#/components/schemas/Image'
          description: Image inputs for the follow-up. Each entry must provide either `data` (with required `mimeType`) or `url`. Maximum 5 images, 15 MB each.

    FollowupRunRequest:
      type: object
      additionalProperties: false
      description: |
        An ordinary follow-up. It starts a new run and returns `201`, or
        returns `409 agent_busy` while another run is active.
      required:
        - prompt
      properties:
        prompt:
          $ref: '#/components/schemas/RunPrompt'
        model:
          $ref: '#/components/schemas/ModelRef'
        mcpServers:
          type: array
          maxItems: 50
          description: Inline MCP server definitions for this follow-up run. When provided, these definitions replace any create-time inline MCP servers for this run.
          items:
            $ref: '#/components/schemas/McpServer'
        envVars:
          allOf:
            - $ref: '#/components/schemas/EnvVars'
          description: |
            Environment variables for this follow-up run only, applied
            while it executes. Names and values follow the `EnvVars`
            rules.
        mode:
          $ref: '#/components/schemas/AgentMode'

    SteerRunRequest:
      type: object
      additionalProperties: false
      description: |
        A steer sends the prompt into the agent's running turn instead of
        starting a new run, and returns `202` with a `SteerRunResponse`.
        It requires `prompt` and `delivery` and accepts no other top-level
        fields. Any other field, such as `model`, `mcpServers`, `envVars`,
        or `mode`, returns `400 validation_error` with a message that
        names the fields, such as
        `"model" is not allowed with delivery "steer"` or
        `"model", "mode" are not allowed with delivery "steer"`.
      required:
        - prompt
        - delivery
      properties:
        prompt:
          $ref: '#/components/schemas/RunPrompt'
        delivery:
          type: string
          enum:
            - steer

    AgentMode:
      type: string
      enum:
        - agent
        - plan
      description: >
        Conversation mode. `plan` explores and drafts a plan before coding;
        `agent` implements changes directly. On follow-up runs, omit to keep
        the conversation's current mode; set explicitly to switch modes for
        that run.

    CreateAgentResponse:
      type: object
      required:
        - agent
        - run
      properties:
        agent:
          $ref: '#/components/schemas/Agent'
        run:
          $ref: '#/components/schemas/Run'

    CreateRunResponse:
      type: object
      required:
        - run
      properties:
        run:
          $ref: '#/components/schemas/Run'

    SteerRunResponse:
      description: |
        What happened to a steered prompt. `delivery` is `steered` or
        `queued`, and only a `steered` response can include `runId`.
      oneOf:
        - $ref: '#/components/schemas/SteeredRunResponse'
        - $ref: '#/components/schemas/QueuedRunResponse'
      discriminator:
        propertyName: delivery
        mapping:
          steered: '#/components/schemas/SteeredRunResponse'
          queued: '#/components/schemas/QueuedRunResponse'

    SteeredRunResponse:
      type: object
      additionalProperties: false
      required:
        - delivery
      properties:
        delivery:
          type: string
          enum:
            - steered
          description: The agent's running turn accepted the prompt.
        runId:
          type: string
          pattern: '^run-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
          description: |
            The run that accepted the steer, which was running when the API
            got it. The prompt reaches that run at its next safe step unless
            the run ends first, in which case the prompt starts the agent's
            next run. Omitted when the agent had no active run.
          example: 'run-00000000-0000-0000-0000-000000000002'

    QueuedRunResponse:
      type: object
      additionalProperties: false
      required:
        - delivery
      properties:
        delivery:
          type: string
          enum:
            - queued
          description: |
            No running turn could take the prompt, so it becomes the
            agent's next follow-up. That includes a steer that lands just
            after the agent's run changed. A `queued` response never
            includes `runId`.

    ListAgentsResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          description: Agents, newest first.
          items:
            $ref: '#/components/schemas/AgentSummary'
        nextCursor:
          type: string
          minLength: 1
          description: Cursor for fetching the next page of results. Omitted (not `null`) when there are no more pages.
          example: 'bc-00000000-0000-0000-0000-000000000002'

    ListRunsResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          description: Runs for this agent, newest first.
          items:
            $ref: '#/components/schemas/Run'
        nextCursor:
          type: string
          minLength: 1
          description: Cursor for fetching the next page of results. Omitted (not `null`) when there are no more pages.

    IdResponse:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          description: Identifier of the affected resource.

    Artifact:
      type: object
      required:
        - path
        - sizeBytes
        - updatedAt
      properties:
        path:
          type: string
          minLength: 1
          description: Artifact path relative to the workspace's `artifacts/` directory.
          example: 'artifacts/screenshot.png'
        sizeBytes:
          type: integer
          minimum: 0
          description: File size in bytes.
          example: 12345
        updatedAt:
          type: string
          format: date-time
          description: Last modified timestamp.

    ListArtifactsResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          description: Artifacts produced by the agent. Returns at most 100 artifacts.
          items:
            $ref: '#/components/schemas/Artifact'

    DownloadArtifactResponse:
      type: object
      required:
        - url
        - expiresAt
      properties:
        url:
          type: string
          format: uri
          description: Temporary 15-minute presigned S3 URL for downloading the artifact.
          example: 'https://cloud-agent-artifacts.s3.us-east-1.amazonaws.com/...'
        expiresAt:
          type: string
          format: date-time
          description: When the presigned URL expires.

    UsageTokenUsage:
      type: object
      required:
        - inputTokens
        - outputTokens
        - cacheWriteTokens
        - cacheReadTokens
        - totalTokens
      properties:
        inputTokens:
          type: integer
          minimum: 0
          description: Input tokens consumed.
          example: 6320
        outputTokens:
          type: integer
          minimum: 0
          description: Output tokens generated.
          example: 1450
        cacheWriteTokens:
          type: integer
          minimum: 0
          description: Tokens written to cache.
          example: 7100
        cacheReadTokens:
          type: integer
          minimum: 0
          description: Tokens read from cache.
          example: 21300
        totalTokens:
          type: integer
          minimum: 0
          description: Sum of the four token counts above.
          example: 36170

    RunUsage:
      type: object
      required:
        - id
        - usage
      properties:
        id:
          type: string
          minLength: 1
          description: Run identifier.
          example: 'run-00000000-0000-0000-0000-000000000001'
        usageUuid:
          type: string
          minLength: 1
          description: Internal usage identifier for the run. Omitted when the run has no recorded usage yet.
          example: '00000000-0000-0000-0000-000000000001'
        usage:
          allOf:
            - $ref: '#/components/schemas/UsageTokenUsage'
          description: Token usage for this run. Runs without recorded usage report zeros across all fields.

    AgentUsageResponse:
      type: object
      required:
        - totalUsage
        - runs
      properties:
        totalUsage:
          allOf:
            - $ref: '#/components/schemas/UsageTokenUsage'
          description: Token usage summed across the returned runs.
        runs:
          type: array
          description: Per-run usage, one entry per run (or a single entry when `runId` is set).
          items:
            $ref: '#/components/schemas/RunUsage'

    EnvironmentRepo:
      type: object
      additionalProperties: false
      required:
        - url
      properties:
        url:
          type: string
          minLength: 1
          description: Repository URL.
          example: 'https://github.com/your-org/your-repo'

    EnvironmentRepoFile:
      type: object
      additionalProperties: false
      description: The file in a repository that an environment reads its configuration from.
      required:
        - url
        - path
      properties:
        url:
          type: string
          minLength: 1
          description: URL of the repository that holds the configuration file.
          example: 'https://github.com/your-org/your-repo'
        path:
          type: string
          minLength: 1
          description: Path of the configuration file in the repository.
          example: '.cursor/environment.json'

    EnvironmentBuildSettings:
      type: object
      additionalProperties: false
      description: The environment's build settings. Whether agents pull the latest code when they start, and how long a build's install step can run.
      required:
        - pullLatestCode
        - stalenessThresholdHours
        - installTimeoutMinutes
      properties:
        pullLatestCode:
          type: string
          enum: ['when_stale', 'never', 'always']
          description: Whether agents that start on the default branch pull its latest code. `when_stale`, the default, pulls when the active build is older than `stalenessThresholdHours`. `never` uses the commit the build recorded. `always` is a legacy value you can read but not set.
        stalenessThresholdHours:
          type: integer
          nullable: true
          minimum: 0
          maximum: 8760
          description: Hours before the active build counts as stale. `0` pulls on every start. `null` means the default, 24.
          example: 24
        installTimeoutMinutes:
          type: integer
          nullable: true
          minimum: 5
          maximum: 300
          description: Minutes a build's install step can run. `null` means the default, 90.
          example: 90

    UpdateEnvironmentBuildSettings:
      type: object
      additionalProperties: false
      minProperties: 1
      description: New values for any of the build settings GET /v1/environments/{id} returns. Fields you leave out stay unchanged, and `null` resets a field to its default.
      properties:
        pullLatestCode:
          type: string
          nullable: true
          enum: ['when_stale', 'never', null]
          description: '`when_stale` (the default) or `never`. Setting the legacy `always` returns `400 validation_error`. To move an environment off `always`, send `when_stale` with `stalenessThresholdHours`.'
        stalenessThresholdHours:
          type: integer
          nullable: true
          minimum: 0
          maximum: 8760
          description: Hours before the active build counts as stale. Default 24.
          example: 12
        installTimeoutMinutes:
          type: integer
          nullable: true
          minimum: 5
          maximum: 300
          description: Minutes a build's install step can run. Default 90.
          example: 120

    Environment:
      type: object
      required:
        - id
        - owner
        - repos
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
          description: Unique environment identifier.
          example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
        name:
          type: string
          minLength: 1
          description: Display name. Omitted when the environment has no name.
          example: 'Web app'
        owner:
          type: string
          enum: ['personal', 'team']
          description: '`personal` for an environment that belongs to one user, or `team` for an environment shared with the team.'
        repos:
          type: array
          description: Repositories in the environment.
          items:
            $ref: '#/components/schemas/EnvironmentRepo'
        createdAt:
          type: string
          format: date-time
          description: When the environment was created.
        updatedAt:
          type: string
          format: date-time
          description: When the environment was last updated.

    CreateEnvironmentResponse:
      allOf:
        - $ref: '#/components/schemas/Environment'
        - type: object
          required:
            - name

    GetEnvironmentResponse:
      allOf:
        - $ref: '#/components/schemas/Environment'
        - type: object
          required:
            - buildSettings
          properties:
            repoFile:
              $ref: '#/components/schemas/EnvironmentRepoFile'
            environmentJson:
              type: string
              description: The environment's latest saved configuration, its `environment.json`, as a JSON-encoded string.
              example: '{"install": "pnpm install", "start": "sudo service docker start"}'
            versionId:
              type: string
              minLength: 1
              description: ID of the latest saved environment version. Omitted when no version has been saved.
              example: 'c9f0f895-fb98-4b91-8f3e-2a1b0c9d8e7f'
            buildSettings:
              $ref: '#/components/schemas/EnvironmentBuildSettings'

    ListEnvironmentsResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          description: Environments, most recently updated first. List items omit `environmentJson`, `versionId`, and `buildSettings`.
          items:
            allOf:
              - $ref: '#/components/schemas/Environment'
              - type: object
                properties:
                  repoFile:
                    $ref: '#/components/schemas/EnvironmentRepoFile'
        nextCursor:
          type: string
          minLength: 1
          description: Cursor for fetching the next page of results. A page can hold fewer items than `limit`, even none, so keep paging until it's absent. Omitted (not `null`) when there are no more pages.

    CreateEnvironmentRequest:
      type: object
      additionalProperties: false
      required:
        - owner
        - name
        - repos
        - environmentJson
      properties:
        owner:
          type: string
          enum: ['personal', 'team']
          description: '`personal` creates an environment for the API key''s user, and `team` creates one for the team.'
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Display name. It must differ from the names of the owner's other environments; a name the owner already uses returns `409 environment_name_conflict`.
          example: 'Web app'
        repos:
          type: array
          maxItems: 500
          description: Repositories for the environment, or an empty array for an environment without repositories. Cursor must be able to reach each one through your source control integration; otherwise the request returns `400 repository_access`.
          items:
            $ref: '#/components/schemas/EnvironmentRepo'
        environmentJson:
          type: string
          minLength: 1
          description: The environment's `environment.json`, as a JSON-encoded string, using the same schema as a `.cursor/environment.json` file. An invalid configuration returns `400 validation_error`.
          example: '{"install": "pnpm install", "start": "sudo service docker start"}'

    UpdateEnvironmentRequest:
      type: object
      additionalProperties: false
      minProperties: 1
      description: Send `name`, `environmentJson`, `repos`, or any combination. `repos` requires `environmentJson`. A request applies every field it sends together, so either all of them change or none do. Send `buildSettings` on its own; a request that also sends `name`, `environmentJson`, or `repos` returns `400 validation_error`.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: New display name. It must differ from the names of the owner's other environments; a name the owner already uses returns `409 environment_name_conflict`.
          example: 'Web app (staging)'
        environmentJson:
          type: string
          description: Replacement `environment.json`, as a JSON-encoded string, using the same schema as a `.cursor/environment.json` file. It replaces the whole configuration. An invalid configuration returns `400 validation_error`. If the environment reads its configuration from a file in its only repository, the request returns `409 repo_file_environment_locked`.
          example: '{"install": "pnpm install --frozen-lockfile", "start": "sudo service docker start"}'
        repos:
          type: array
          maxItems: 500
          description: |
            The environment's full list of repositories, replacing the
            current list. It follows the same rules as `repos` on
            POST /v1/environments. Send `environmentJson` with it, because a
            repository change saves the whole configuration; `repos` without
            `environmentJson` returns `400 validation_error`. To keep the
            current configuration, send the `environmentJson` from
            GET /v1/environments/{id}.

            Only environments with two or more repositories can change them,
            and they must keep at least two. Sending the current list
            unchanged doesn't count as a change. Otherwise an environment
            without repositories, a single-repository environment, or a list
            with fewer than two returns `409 environment_repo_edit_blocked`.

            When the environment reads its configuration from a repository
            file (`repoFile` on GET /v1/environments/{id}), the file stays the
            configuration source. The list must keep the `repoFile.url`
            repository, or the request returns `409 repo_file_repo_removed`.
            Repositories are compared by identity, so a trailing `.git` or
            slash, a missing scheme, a leading `www.`, or GitHub letter case
            still match. When the list names that repository in several forms,
            the first entry is kept and the others dropped. For Bitbucket
            Server, send the URL GET returns. An environment whose
            only repository holds its configuration file returns
            `409 repo_file_environment_locked` for any `repos`. Stored
            repositories Cursor can't read return
            `400 stored_repos_unreadable`.
          items:
            $ref: '#/components/schemas/EnvironmentRepo'
        buildSettings:
          $ref: '#/components/schemas/UpdateEnvironmentBuildSettings'

    EnvironmentBuildId:
      type: string
      pattern: '^[bB][lL][dD]-[0-9]{8}-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
      description: Unique build identifier, in the form `bld-YYYYMMDD-<uuid>`.
      example: 'bld-20260930-3c59dc04-8a1d-4b6e-9f2a-7e5d1c0b9a8f'

    StartEnvironmentBuildRequest:
      type: object
      additionalProperties: false
      description: Send no body, or `{}`, for a non-draft build of every repository's default branch.
      properties:
        draft:
          type: boolean
          default: false
          description: '`true` for a draft build, which agents don''t start from until it''s activated. A non-draft build is what agents start from once it succeeds.'
        refs:
          type: array
          description: Branches to build instead of the default branches. Repositories without an entry build their default branch, and a ref that names the default branch counts as no entry. Any other branch requires `draft` set to `true`; without it, and for a repository that isn't in the environment or a second ref for the same repository, the request returns `400 validation_error`. Cursor doesn't check that the branch exists, so a missing branch fails the build, not the request.
          items:
            $ref: '#/components/schemas/StartEnvironmentBuildRef'

    StartEnvironmentBuildRef:
      type: object
      additionalProperties: false
      required:
        - repoUrl
        - ref
      properties:
        repoUrl:
          type: string
          minLength: 1
          pattern: '\S'
          description: One of the environment's repositories.
          example: 'https://github.com/your-org/your-web-app'
        ref:
          type: string
          minLength: 1
          pattern: '\S'
          description: Branch name to build the repository from.
          example: 'feature/new-checkout'

    StartEnvironmentBuildResponse:
      type: object
      additionalProperties: false
      required:
        - id
        - environmentId
      properties:
        id:
          $ref: '#/components/schemas/EnvironmentBuildId'
        environmentId:
          type: string
          format: uuid
          description: Environment ID.
          example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'

    EnvironmentBuildFailure:
      type: object
      additionalProperties: false
      description: Why a failed build failed.
      required:
        - type
      properties:
        type:
          type: string
          enum: ['INSTALL_FAILED', 'TERMINAL_FAILURE']
          description: '`INSTALL_FAILED` when the `install` command failed, or `TERMINAL_FAILURE` for other failures.'
        code:
          type: string
          minLength: 1
          description: Machine-readable cause of the failure, when there is one.
          example: 'environment_json_invalid'

    EnvironmentBuildRequestedRef:
      type: object
      additionalProperties: false
      description: The branch, tag, or commit a build was asked to use for one repository.
      required:
        - repoUrl
        - ref
      properties:
        repoUrl:
          type: string
          minLength: 1
          description: Repository URL.
          example: 'https://github.com/your-org/your-web-app'
        ref:
          type: string
          minLength: 1
          description: Branch, tag, or commit SHA the build was asked to use instead of the repository's default branch.
          example: 'feature/new-checkout'

    EnvironmentBuildRepoCommit:
      type: object
      additionalProperties: false
      description: The commit a build checked out for one repository.
      required:
        - repoUrl
        - commitSha
      properties:
        repoUrl:
          type: string
          minLength: 1
          description: Repository URL.
          example: 'https://github.com/your-org/your-web-app'
        commitSha:
          type: string
          minLength: 1
          description: SHA of the commit the build checked out.
          example: '06b7d943cd0e7ea353ca932d5cdea8987b8e8105'

    EnvironmentBuild:
      type: object
      additionalProperties: false
      required:
        - id
        - environmentId
        - status
        - trigger
        - source
        - draft
        - requestedRefs
        - repoCommits
        - createdAt
        - updatedAt
      properties:
        id:
          $ref: '#/components/schemas/EnvironmentBuildId'
        environmentId:
          type: string
          format: uuid
          description: ID of the environment the build belongs to.
          example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
        status:
          type: string
          enum: ['IN_PROGRESS', 'SUCCEEDED', 'FAILED', 'CANCELLED', 'SKIPPED']
          description: Build status. A skipped build found nothing to rebuild.
        trigger:
          type: string
          enum: ['RECURRING', 'CONFIG_CHANGE', 'MANUAL']
          description: What started the build. `RECURRING` for a scheduled build, `CONFIG_CHANGE` after a configuration or secrets change, or `MANUAL` for one started on request.
        source:
          type: string
          enum: ['SYSTEM', 'WEBSITE', 'API', 'AGENT']
          description: Where the build was started from. `SYSTEM` (Cursor on its own), `WEBSITE` (the dashboard), `API`, or `AGENT` (a cloud agent).
        draft:
          type: boolean
          description: '`true` for a draft build. Agents don''t start from a draft build until it''s activated.'
        failure:
          $ref: '#/components/schemas/EnvironmentBuildFailure'
        requestedRefs:
          type: array
          description: Branches, tags, or commits the build was asked to use instead of a repository's default branch. Repositories without an entry use their default branch. An API key limited to certain repositories sees only entries for repositories inside its limit.
          items:
            $ref: '#/components/schemas/EnvironmentBuildRequestedRef'
        repoCommits:
          type: array
          description: Repository commits returned for the build, when available. An API key limited to certain repositories sees only entries inside its limit.
          items:
            $ref: '#/components/schemas/EnvironmentBuildRepoCommit'
        snapshotState:
          type: string
          enum: ['ACTIVE', 'REAP_REQUESTED', 'DELETED']
          description: State of the build's snapshot. Omitted if the build didn't create a snapshot.
        createdAt:
          type: string
          format: date-time
          description: When the build was created.
        updatedAt:
          type: string
          format: date-time
          description: When the build was last updated.
        completedAt:
          type: string
          format: date-time
          description: When the build finished. Omitted while it's in progress.

    ListEnvironmentBuildsResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          maxItems: 100
          description: Up to `limit` builds for this environment, newest first.
          items:
            $ref: '#/components/schemas/EnvironmentBuild'
        nextCursor:
          type: string
          minLength: 1
          description: Cursor for fetching the next page of results. Omitted (not `null`) when there are no more pages.

    EnvironmentActiveBuild:
      description: What an agent you start on this environment boots from, one of its builds or Cursor's default image.
      oneOf:
        - $ref: '#/components/schemas/EnvironmentActiveBuildFromBuild'
        - $ref: '#/components/schemas/EnvironmentActiveBuildFromUniversalImage'
      discriminator:
        propertyName: type
        mapping:
          build: '#/components/schemas/EnvironmentActiveBuildFromBuild'
          universal_image: '#/components/schemas/EnvironmentActiveBuildFromUniversalImage'

    EnvironmentActiveBuildFromBuild:
      type: object
      additionalProperties: false
      description: The agent starts from one of the environment's builds.
      required:
        - type
        - buildId
      properties:
        type:
          type: string
          enum: ['build']
        buildId:
          $ref: '#/components/schemas/EnvironmentBuildId'

    EnvironmentActiveBuildFromUniversalImage:
      type: object
      additionalProperties: false
      description: The agent starts on Cursor's default image.
      required:
        - type
      properties:
        type:
          type: string
          enum: ['universal_image']

    EnvironmentHistoryEvent:
      type: object
      additionalProperties: false
      required:
        - id
        - createdAt
        - kind
        - title
        - description
        - current
      properties:
        id:
          type: string
          minLength: 1
          description: Unique event identifier.
          example: '3b7e1f2a-9c4d-4e8b-a1f6-5d2c8e9b0a17'
        createdAt:
          type: string
          format: date-time
          description: When the change was made.
        kind:
          type: string
          enum: ['created', 'updated', 'deleted', 'backfilled', 'changed']
        title:
          type: string
          description: The event's summary, as the History tab shows it.
          example: 'Team environment updated'
        description:
          type: string
          description: The event's details, as the History tab shows them.
          example: 'Install script changed.'
        source:
          type: string
          enum: ['dashboard', 'setup_flow', 'restore', 'api', 'agent_run', 'repo_file', 'request_override']
          description: Where the change came from.
        current:
          type: boolean
          description: '`true` for the event that saved the environment''s current configuration.'
        environmentJson:
          type: string
          description: The `environment.json` the event saved, as a JSON-encoded string.
          example: '{"install": "pnpm install", "start": "sudo service docker start"}'

    ListEnvironmentHistoryResponse:
      type: object
      additionalProperties: false
      required:
        - items
      properties:
        items:
          type: array
          description: History events, newest first.
          items:
            $ref: '#/components/schemas/EnvironmentHistoryEvent'
        nextCursor:
          type: string
          minLength: 1
          description: Cursor for fetching the next page of results. Omitted (not `null`) when there are no more pages.

    ApiKeyInfo:
      type: object
      required:
        - apiKeyName
        - createdAt
      properties:
        apiKeyName:
          type: string
          description: Display name of the API key.
          example: 'Production API Key'
        createdAt:
          type: string
          format: date-time
          description: When the API key was created.
        userId:
          type: integer
          minimum: 0
          description: Numeric Cursor user ID of the API key's owner. Omitted for service-account / team API keys, which aren't tied to a specific user.
          example: 42
        userEmail:
          type: string
          format: email
          description: Email of the API key's owner. Omitted for service-account / team API keys.
          example: 'developer@example.com'
        userFirstName:
          type: string
          minLength: 1
          description: First name of the API key's owner, when populated.
          example: 'Alex'
        userLastName:
          type: string
          minLength: 1
          description: Last name of the API key's owner, when populated.
          example: 'Rivera'

    ModelParameterValueDefinition:
      type: object
      required:
        - value
      properties:
        value:
          type: string
          minLength: 1
          description: Permitted value for the parameter.
          example: 'true'
        displayName:
          type: string
          minLength: 1
          description: Human-readable label for the value.
          example: 'Fast'

    ModelParameterDefinition:
      type: object
      required:
        - id
        - values
      properties:
        id:
          type: string
          minLength: 1
          description: Parameter identifier. Pass as `model.params[].id`.
          example: 'fast'
        displayName:
          type: string
          minLength: 1
          description: Human-readable label for the parameter.
          example: 'Fast'
        values:
          type: array
          minItems: 1
          description: Permitted values for this parameter.
          items:
            $ref: '#/components/schemas/ModelParameterValueDefinition'

    ModelVariant:
      type: object
      required:
        - params
        - displayName
      properties:
        params:
          type: array
          description: Concrete parameter values that, combined with the parent model `id`, form a valid model selection. May be empty.
          items:
            type: object
            required:
              - id
              - value
            properties:
              id:
                type: string
                minLength: 1
              value:
                type: string
                minLength: 1
        displayName:
          type: string
          minLength: 1
          description: Human-readable label for this variant.
        description:
          type: string
          minLength: 1
        isDefault:
          type: boolean
          description: True for the variant Cursor selects when the user picks this model without explicit `params`.

    ModelListItem:
      type: object
      required:
        - id
        - displayName
      properties:
        id:
          type: string
          minLength: 1
          description: Pass this value as `model.id` when creating an agent.
          example: 'composer-2'
        displayName:
          type: string
          minLength: 1
          description: Human-readable model name.
          example: 'Composer 2'
        description:
          type: string
          minLength: 1
        aliases:
          type: array
          description: Alternate IDs that resolve to the same model.
          items:
            type: string
            minLength: 1
          example: ['composer-latest', 'composer']
        parameters:
          type: array
          description: Per-model parameter definitions, when the model accepts parameters. Use these to populate `model.params`.
          items:
            $ref: '#/components/schemas/ModelParameterDefinition'
        variants:
          type: array
          description: Concrete `id`+`params` combinations the model accepts.
          items:
            $ref: '#/components/schemas/ModelVariant'

    ListModelsResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          description: Recommended models. Use `id` (and optionally `params`) when creating an agent.
          items:
            $ref: '#/components/schemas/ModelListItem'

    SecretVersion:
      type: object
      description: |
        One version of a Cloud Agents secret. A name can have several
        versions in one environment, team, or user's personal secrets,
        each for repositories the others don't cover. Responses never
        include a secret's value.
      required:
        - name
        - type
        - repos
      properties:
        id:
          type: string
          pattern: '^secv_[A-Za-z0-9_-]{22}$'
          description: |
            Opaque version ID. A version keeps its `id` through changes to
            its value, type, or repositories. Always present in lists; a
            `201` from a `PUT` leaves it out when the new version isn't
            readable yet.
          example: 'secv_3qKx9mT2bV7nR1cW5yZ8aQ'
        name:
          type: string
          description: Environment variable name agents see.
          example: 'NPM_TOKEN'
        type:
          type: string
          enum:
            - runtime_secret
            - environment_variable
            - build_secret
          description: |
            `runtime_secret` for a Runtime Secret, `environment_variable`
            for an Environment Variable, or `build_secret` for a Build
            Secret, which only the Docker build gets.
          example: 'runtime_secret'
        repos:
          type: array
          items:
            type: string
          description: |
            The only repositories that get this version, lowercase and
            sorted, with repository URLs reduced to `host/owner/repo`.
            Empty when every repository gets it.
          example:
            - 'github.com/acme/api'
        createdAt:
          type: string
          format: date-time
          description: |
            When the version was created. Always present in lists; a
            `201` from a `PUT` leaves it out when the new version isn't
            readable yet.
          example: '2026-10-01T09:15:42.000Z'

    Repository:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          description: GitHub repository URL.
          example: 'https://github.com/your-org/your-repo'

    ListSecretsResponse:
      type: object
      required:
        - items
        - nextCursor
      properties:
        items:
          type: array
          description: |
            Secret versions, sorted by name. A name with versions for
            different repositories appears once per version.
          items:
            allOf:
              - $ref: '#/components/schemas/SecretVersion'
              - type: object
                required:
                  - id
                  - createdAt
        nextCursor:
          type: string
          nullable: true
          description: |
            Cursor for the next page. Always `null` for now, because the
            list isn't paginated yet.
          example: null

    SecretInventoryOwner:
      type: object
      description: |
        Who holds a secret version: `team` for the team the API key works
        in, `user` for a user's personal secrets, or `environment` for an
        environment's secrets.
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - team
            - user
            - environment
          example: 'environment'
        environmentId:
          type: string
          format: uuid
          description: The environment, for an `environment` owner.
          example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
        user:
          type: object
          description: |
            The user who owns the secrets, for a `user` owner and a personal
            environment. Absent for the team and its environments.
          required:
            - email
          properties:
            email:
              type: string
              nullable: true
              description: The user's email, or `null` when the user has none on file.
              example: 'ada@acme.com'

    InventorySecretVersion:
      type: object
      description: |
        A secret version with the owner that holds it. Responses never
        include a secret's value.
      required:
        - id
        - name
        - type
        - repos
        - createdAt
        - owner
      properties:
        id:
          type: string
          pattern: '^secv_[A-Za-z0-9_-]{22}$'
          description: The version ID its owner's own list shows.
          example: 'secv_3qKx9mT2bV7nR1cW5yZ8aQ'
        name:
          type: string
          description: Environment variable name agents see.
          example: 'NPM_TOKEN'
        type:
          type: string
          enum:
            - runtime_secret
            - environment_variable
            - build_secret
          example: 'runtime_secret'
        repos:
          type: array
          items:
            type: string
          description: |
            The only repositories that get this version, or empty when every
            repository gets it. Every version has it, including other
            members' versions in a team admin's list.
          example:
            - 'github.com/acme/api'
        createdAt:
          type: string
          format: date-time
          description: When the version was created.
          example: '2026-10-01T09:15:42.000Z'
        owner:
          $ref: '#/components/schemas/SecretInventoryOwner'

    ListSecretInventoryResponse:
      type: object
      required:
        - items
        - nextCursor
      properties:
        items:
          type: array
          description: |
            Secret versions with their owners, not sorted by name. Other
            members' versions come after the rest.
          items:
            $ref: '#/components/schemas/InventorySecretVersion'
        nextCursor:
          type: string
          nullable: true
          description: |
            Cursor for the next page, or `null` on the last page. A page can
            hold fewer than `limit` items, or none, and still have one.
          example: null

    ListRepositoriesResponse:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Repository'

    SetSecretRequest:
      type: object
      additionalProperties: false
      required:
        - value
      properties:
        value:
          type: string
          minLength: 1
          description: |
            The secret's value, 1 to 4,096 bytes of UTF-8 text. No
            response or error message includes it.
          example: 'npm_example_token'
        type:
          type: string
          enum:
            - runtime_secret
            - environment_variable
          description: |
            A new version defaults to `runtime_secret`. A change without
            `type` keeps the version's type. Build Secrets can't be set
            through the API yet.
          example: 'runtime_secret'
        repos:
          type: array
          maxItems: 100
          items:
            type: string
            minLength: 1
          description: |
            The only repositories that get this version, such as
            `acme/api`, `https://github.com/acme/api.git`, or
            `gitlab.com/group/subgroup/project`. An empty array, or
            omitting `repos` on a new version, gives it every repository.
            A change without `repos` keeps the version's repositories.
          example:
            - 'github.com/acme/api'

    SecretVersionSummary:
      type: object
      required:
        - id
        - repos
      properties:
        id:
          type: string
          description: The version's `id`. Pass it as `?id=` to pick this version.
          example: 'secv_3qKx9mT2bV7nR1cW5yZ8aQ'
        repos:
          type: array
          items:
            type: string
          description: The only repositories that get this version.
          example:
            - 'github.com/acme/api'

    SecretNameAmbiguousError:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - versions
          properties:
            code:
              type: string
              enum:
                - secret_name_ambiguous
            message:
              type: string
              example: 'NPM_TOKEN has 2 versions, each for different repos. Pass the id of one as ?id= to pick it.'
            versions:
              type: array
              description: Every version of the name, in list order.
              items:
                $ref: '#/components/schemas/SecretVersionSummary'

    CreateSubTokenRequest:
      type: object
      description: Provide exactly one active team member identifier.
      properties:
        forUserEmail:
          type: string
          format: email
          minLength: 1
          description: Active team member email. Case-insensitive. Mutually exclusive with `forUserId`.
          example: 'alice@company.com'
        forUserId:
          type: integer
          minimum: 1
          description: Active team member's numeric Cursor user ID. Mutually exclusive with `forUserEmail`.
          example: 42
      oneOf:
        - required: [forUserEmail]
          not:
            required: [forUserId]
        - required: [forUserId]
          not:
            required: [forUserEmail]

    DeleteSecretResponse:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: Name of the deleted secret.
          example: 'NPM_TOKEN'

    CreateSubTokenResponse:
      type: object
      required:
        - accessToken
        - expiresAt
        - userId
        - teamId
      properties:
        accessToken:
          type: string
          minLength: 1
          description: Short-lived access token scoped to the requested user. Pass this to the worker with --auth-token or write it to the file used by --auth-token-file.
          example: 'eyJ...'
        expiresAt:
          type: string
          format: date-time
          description: When the access token expires (1 hour after mint).
          example: '2026-04-24T19:00:00.000Z'
        userId:
          type: integer
          description: Numeric ID of the resolved team member.
          example: 42
        teamId:
          type: integer
          description: Numeric ID of the service account's team.
          example: 456

    AuthenticationError:
      type: object
      description: Body of a `401` response when the API key fails authentication.
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Error category, such as `error`.
          example: 'error'
        message:
          type: string
          description: Human-readable error message.
          example: 'Invalid User API Key'

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: |
                Machine-readable error code. Possible values include
                `unauthorized`, `api_key_not_found`, `plan_required`,
                `role_forbidden`, `feature_unavailable`, `key_not_supported`,
                `integration_not_connected`, `validation_error`,
                `missing_body`, `invalid_model`, `invalid_branch_name`,
                `repository_required`, `repository_access`,
                `pr_resolution_failed`, `artifact_not_found`,
                `service_account_required`, `agent_not_found`,
                `run_not_found`, `environment_not_found`, `build_not_found`,
                `team_admin_required`, `environment_name_conflict`,
                `environment_repo_edit_blocked`, `repo_file_repo_removed`,
                `repo_file_environment_locked`, `stored_repos_unreadable`,
                `duplicate_json_key`, `agent_busy`, `agent_archived`,
                `agent_id_conflict`, `run_not_cancellable`,
                `rate_limit_exceeded`, `usage_limit_exceeded`,
                `stream_expired`, `stream_unavailable`,
                `invalid_last_event_id`, `client_cancelled`,
                `not_implemented`, `upstream_error`, and
                `internal_error`.
            message:
              type: string
              description: Human-readable error message.
            helpUrl:
              type: string
              format: uri
              description: Optional follow-up link. Populated for codes like `integration_not_connected`.
            provider:
              type: string
              minLength: 1
              description: Optional provider identifier. Populated for codes like `integration_not_connected`.
            environmentId:
              type: string
              format: uuid
              description: ID of the existing environment with the requested name, when an `environment_name_conflict` error returns it.
              example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'

  parameters:
    AgentId:
      name: id
      in: path
      required: true
      description: Unique identifier for the agent.
      schema:
        type: string
        example: 'bc-00000000-0000-0000-0000-000000000001'
    RunId:
      name: runId
      in: path
      required: true
      description: Unique identifier for the run.
      schema:
        type: string
        example: 'run-00000000-0000-0000-0000-000000000001'
    EnvironmentId:
      name: id
      in: path
      required: true
      description: Unique identifier for the environment.
      schema:
        type: string
        format: uuid
        example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
    EnvironmentBuildId:
      name: buildId
      in: path
      required: true
      description: Unique identifier for the build.
      schema:
        $ref: '#/components/schemas/EnvironmentBuildId'

  responses:
    BadRequest:
      description: Validation error or malformed request body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Invalid, missing, or unsupported API key. When the API key fails authentication, the body has a top-level `code` and `message` instead of an `error` object.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/AuthenticationError'
              - $ref: '#/components/schemas/Error'
    Forbidden:
      description: Authenticated but insufficient permissions, plan required, or feature unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Resource state conflict (`agent_busy`, `agent_archived`, `agent_id_conflict`, `run_not_cancellable`, or `environment_name_conflict`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Gone:
      description: Stream retention window has elapsed (`stream_expired`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Rate limit exceeded. Response includes `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

paths:
  /v1/agents:
    post:
      summary: Create an agent
      description: |
        Create a Cloud Agent and immediately enqueue its initial run.
        The response contains both the durable `agent` and the initial
        `run`.
      operationId: createAgent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentRequest'
      responses:
        '201':
          description: Agent created and initial run enqueued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateAgentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
    get:
      summary: List agents
      description: List agents for the authenticated user, newest first.
      operationId: listAgents
      parameters:
        - name: limit
          in: query
          required: false
          description: Number of agents to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          required: false
          description: Pagination cursor from the previous response.
          schema:
            type: string
            minLength: 1
        - name: prUrl
          in: query
          required: false
          description: Filter agents by GitHub pull request URL.
          schema:
            type: string
            format: uri
        - name: includeArchived
          in: query
          required: false
          description: Whether to include archived agents.
          schema:
            type: boolean
            default: true
      responses:
        '200':
          description: Agents retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListAgentsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}:
    get:
      summary: Get an agent
      description: Retrieve durable metadata for an agent. Execution status lives on runs.
      operationId: getAgent
      parameters:
        - $ref: '#/components/parameters/AgentId'
      responses:
        '200':
          description: Agent retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
    delete:
      summary: Delete an agent permanently
      description: Permanently delete an agent. This action is irreversible. Use POST /v1/agents/{id}/archive for reversible removal.
      operationId: deleteAgent
      parameters:
        - $ref: '#/components/parameters/AgentId'
      responses:
        '200':
          description: Agent deleted successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/runs:
    post:
      summary: Send a follow-up or steer
      description: |
        Send a follow-up prompt to an existing active agent. Without
        `delivery`, the prompt starts a new run that uses the agent's
        current conversation and workspace state, and only one run can
        be active per agent at a time. With `delivery: steer`, the
        agent's running turn takes the prompt when it can, and otherwise
        the prompt becomes the agent's next follow-up. On success, a
        steer returns `202` with no run object. `delivery` says what
        happened, and a `steered` response can include `runId`.
      operationId: createRun
      parameters:
        - $ref: '#/components/parameters/AgentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateRunRequest'
      responses:
        '201':
          description: Run created and enqueued. Returned for a request without `delivery`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateRunResponse'
        '202':
          description: Steer accepted. Returned for `delivery` set to `steer`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SteerRunResponse'
              examples:
                steered:
                  summary: The running turn accepted the prompt
                  value:
                    delivery: steered
                    runId: run-00000000-0000-0000-0000-000000000002
                queued:
                  summary: The prompt becomes the next follow-up
                  value:
                    delivery: queued
        '400':
          description: Validation error or malformed request body. Steering adds two `validation_error` cases, a steer body with any top-level field besides `prompt` and `delivery` or a `delivery` other than `steer`, and a steer that Cursor refuses. For extra fields on a steer, the message names them, such as `"model" is not allowed with delivery "steer"` or `"model", "mode" are not allowed with delivery "steer"`. Cursor checks the body before it checks whether steering is available.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Authenticated but insufficient permissions, plan required, or feature unavailable (`feature_unavailable`), including a steer when steering isn't available for your account.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The agent already has an active run and the request has no `delivery` (`agent_busy`), or the agent is archived (`agent_archived`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
    get:
      summary: List runs
      description: List runs for an agent, newest first.
      operationId: listRuns
      parameters:
        - $ref: '#/components/parameters/AgentId'
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          required: false
          description: Pagination cursor from the previous response.
          schema:
            type: string
            minLength: 1
      responses:
        '200':
          description: Runs retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListRunsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/runs/{runId}:
    get:
      summary: Get a run
      description: Retrieve status and timestamps for a specific run.
      operationId: getRun
      parameters:
        - $ref: '#/components/parameters/AgentId'
        - $ref: '#/components/parameters/RunId'
      responses:
        '200':
          description: Run retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Run'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/runs/{runId}/stream:
    get:
      summary: Stream a run
      description: |
        Stream Server-Sent Events for one run. Event types are
        `status`, `assistant`, `thinking`, `tool_call`,
        `interaction_update`, `heartbeat`, `result`, `error`, and
        `done`.

        - `status` carries `{ runId, status }`. It has no `id` line
          and is replayed at the top of every reconnect.
        - `result` carries `{ runId, status, text?, durationMs?,
          git? }`; `text` is the final assistant reply, `durationMs`
          the wall-clock duration, and `git` mirrors `Run.git`.
        - `interaction_update` carries the richer SDK-shape update
          used by the TypeScript SDK and is emitted alongside the
          simplified events that share the same event id. Use this if
          you want the full SDK stream; otherwise handle the simplified
          events and ignore it.

        Reconnect with the `Last-Event-ID` header to resume after a
        disconnect; the event ID must belong to the requested run
        otherwise the endpoint returns `400 invalid_last_event_id`.
        Responses include the `X-Cursor-Stream-Retention-Seconds`
        header; after the retention window the endpoint may return
        `410 stream_expired`. `tool_call` event data uses the
        `RunStreamToolCallData` schema.
      operationId: streamRun
      parameters:
        - $ref: '#/components/parameters/AgentId'
        - $ref: '#/components/parameters/RunId'
        - name: Last-Event-ID
          in: header
          required: false
          description: Resume from a previously received event ID for this run.
          schema:
            type: string
      responses:
        '200':
          description: SSE stream of run events.
          headers:
            X-Cursor-Stream-Retention-Seconds:
              description: Server-side stream retention window in seconds.
              schema:
                type: integer
          content:
            text/event-stream:
              schema:
                type: string
              examples:
                toolCall:
                  summary: Tool call events
                  value: |
                    id: 1713033005000-0
                    event: tool_call
                    data: {"callId":"call-1","name":"read_file","status":"running","args":{"path":"README.md"}}

                    id: 1713033006000-0
                    event: tool_call
                    data: {"callId":"call-1","name":"read_file","status":"completed","args":{"path":"README.md"},"result":{"success":{"content":"# Project","totalLines":1,"fileSize":9,"path":"README.md"}}}
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '410':
          $ref: '#/components/responses/Gone'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/runs/{runId}/cancel:
    post:
      summary: Cancel a run
      description: |
        Cancel the active run for an agent. Cancellation is terminal —
        the run transitions to `CANCELLED`. Cancelling a run that is
        already terminal or was never active returns
        `409 run_not_cancellable`. To continue the conversation,
        create a new run on the same agent.
      operationId: cancelRun
      parameters:
        - $ref: '#/components/parameters/AgentId'
        - $ref: '#/components/parameters/RunId'
      responses:
        '200':
          description: Run cancelled successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/usage:
    get:
      summary: Get agent usage
      description: |
        Retrieve token usage for an agent, broken down per run.
        `totalUsage` sums input, output, and cache token counts across
        every run on the agent, and `runs` lists the same breakdown for
        each run. Token usage mirrors the `tokenUsage` shape on the team
        usage events endpoint.

        This endpoint is in early access. When it isn't enabled for the
        account it returns `403 feature_unavailable`. An unknown `runId`
        returns `404 run_not_found`.
      operationId: getAgentUsage
      parameters:
        - $ref: '#/components/parameters/AgentId'
        - name: runId
          in: query
          required: false
          description: Scope usage to a single run. Omit to return usage for every run on the agent.
          schema:
            type: string
            example: 'run-00000000-0000-0000-0000-000000000001'
      responses:
        '200':
          description: Usage retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentUsageResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/archive:
    post:
      summary: Archive an agent
      description: Archive an agent. Archived agents remain readable but cannot accept new runs until unarchived.
      operationId: archiveAgent
      parameters:
        - $ref: '#/components/parameters/AgentId'
      responses:
        '200':
          description: Agent archived successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/unarchive:
    post:
      summary: Unarchive an agent
      description: Unarchive an agent so it can accept new runs again.
      operationId: unarchiveAgent
      parameters:
        - $ref: '#/components/parameters/AgentId'
      responses:
        '200':
          description: Agent unarchived successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/artifacts:
    get:
      summary: List artifacts
      description: |
        List artifacts produced by an agent. Each artifact's `path` is
        relative to the workspace's `artifacts/` directory. Pass that
        `path` to GET /v1/agents/{id}/artifacts/download to obtain a
        presigned download URL.
      operationId: listArtifacts
      parameters:
        - $ref: '#/components/parameters/AgentId'
      responses:
        '200':
          description: Artifacts retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListArtifactsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/agents/{id}/artifacts/download:
    get:
      summary: Download an artifact
      description: |
        Retrieve a temporary 15-minute presigned S3 URL for an
        artifact. The `path` query parameter must be a relative path
        under `artifacts/` returned by GET /v1/agents/{id}/artifacts.
      operationId: downloadArtifact
      parameters:
        - $ref: '#/components/parameters/AgentId'
        - name: path
          in: query
          required: true
          description: Relative artifact path under `artifacts/`.
          schema:
            type: string
            minLength: 1
            example: 'artifacts/screenshot.png'
      responses:
        '200':
          description: Presigned URL retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadArtifactResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/environments:
    get:
      summary: List environments
      description: |
        List the saved environments the API key can access, most recently
        updated first. Without `userId`, the list includes the user's
        personal environments and the team's environments. Team admins can
        list another current member's personal environments only by passing
        that member's `userId`.

        Team admins and service account API keys see every team
        environment. Other callers see a team environment only when they
        can access all of its repositories. When those checks run out of
        time, a response can leave out team environments it hasn't
        verified yet, or stop before the end of the list; they show up in
        later requests. A service account API key limited to specific
        repositories, and user-scoped tokens minted with it, only list
        environments that have repositories, all within that limit. Drafts
        and deleted environments aren't included.

        Filters combine: the list keeps only environments that match every
        filter in the request. An invalid filter value returns
        `400 validation_error`.

        An environment that changes during a walk moves to the front, so a
        later page can leave it out and repeat another. List items omit
        `environmentJson`, `versionId`, and `buildSettings`; call
        GET /v1/environments/{id} to load them.
      operationId: listEnvironments
      parameters:
        - name: query
          in: query
          required: false
          description: Only environments whose name contains this text, ignoring case.
          schema:
            type: string
            minLength: 1
            maxLength: 255
        - name: owner
          in: query
          required: false
          description: Only environments with this `owner`.
          schema:
            type: string
            enum: ['personal', 'team']
        - name: named
          in: query
          required: false
          description: '`true` for only environments with a `name`, or `false` for only environments without one.'
          schema:
            type: boolean
        - name: repo
          in: query
          required: false
          description: |
            Only environments that include this repository. Repeat it, up to
            100 times, to list environments that include any of the
            repositories.
          style: form
          explode: true
          schema:
            type: array
            maxItems: 100
            items:
              type: string
              minLength: 1
              example: 'github.com/acme/api'
        - name: userId
          in: query
          required: false
          description: |
            Only one user's personal environments, by the numeric `userId`
            from GET /v1/me or the `user_` ID from the Admin API's team
            members list. Your own ID lists your personal environments. A
            team admin's user API key can also pass a current team member's
            ID, and gets that member's personal environments that have at
            least one repository, all of which the admin can read. A valid ID
            for a user you aren't allowed to list returns `items: []` with no
            `nextCursor`, not an error. Combining `userId` with `owner=team`
            returns `400 validation_error`.
          schema:
            type: string
            minLength: 1
            example: 'user_PDSPmvukpYgZEDXsoNirw3CFhy'
        - name: limit
          in: query
          required: false
          description: Number of environments to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          required: false
          description: Pagination cursor from the previous response. Send the same filters with each `cursor`.
          schema:
            type: string
            minLength: 1
      responses:
        '200':
          description: Environments retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListEnvironmentsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
    post:
      summary: Create an environment
      description: Create a saved environment. The `201` response is the new environment.
      operationId: createEnvironment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEnvironmentRequest'
      responses:
        '201':
          description: Environment created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateEnvironmentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          description: Cursor couldn't reach your source control provider to check a repository (`upstream_error`). Retry after the number of seconds in `Retry-After`.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /v1/environments/{id}:
    get:
      summary: Get an environment
      description: Retrieve a saved environment, its latest saved configuration, and its build settings. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`.
      operationId: getEnvironment
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
      responses:
        '200':
          description: Environment retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetEnvironmentResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
    patch:
      summary: Update an environment
      description: Rename an environment, replace its configuration, replace its repositories, or any combination. A request applies every field it sends together, so either all of them change or none do. Change build settings with `buildSettings` in a request of its own. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`.
      operationId: updateEnvironment
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEnvironmentRequest'
      responses:
        '204':
          description: Environment updated. The response has no body.
        '400':
          description: Validation error or malformed request body (`validation_error`), a repository Cursor can't reach (`repository_access`), or stored repositories Cursor can't read when the request sends `repos` (`stored_repos_unreadable`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The name is taken (`environment_name_conflict`), the environment can't make this repository change (`environment_repo_edit_blocked`), `repos` leaves out the repository that holds the configuration file (`repo_file_repo_removed`), or the environment is locked to its configuration file (`repo_file_environment_locked`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          description: Cursor couldn't reach your source control provider to check a repository (`upstream_error`). Retry after the number of seconds in `Retry-After`.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete an environment
      description: Permanently delete a saved environment. This action is irreversible.
      operationId: deleteEnvironment
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
      responses:
        '200':
          description: Environment deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/environments/{id}/history:
    get:
      summary: List environment history
      description: List the changes to an environment, newest first, as its History tab in the dashboard shows them. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`.
      operationId: listEnvironmentHistory
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
        - name: limit
          in: query
          required: false
          description: Number of events to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          required: false
          description: Pagination cursor from `nextCursor` on the previous response.
          schema:
            type: string
            minLength: 1
      responses:
        '200':
          description: History retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListEnvironmentHistoryResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/environments/{id}/builds:
    get:
      summary: List environment builds
      description: List an environment's builds, newest first. Filter them by status or creation time. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`.
      operationId: listEnvironmentBuilds
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
        - name: status
          in: query
          required: false
          description: Only builds with this status.
          schema:
            type: string
            enum: ['IN_PROGRESS', 'SUCCEEDED', 'FAILED', 'CANCELLED', 'SKIPPED']
        - name: createdAfter
          in: query
          required: false
          description: Only builds created at or after this time. Use an ISO 8601 timestamp with `Z` or a UTC offset and at most millisecond precision.
          schema:
            type: string
            format: date-time
            example: '2026-09-29T00:00:00Z'
        - name: createdBefore
          in: query
          required: false
          description: Only builds created before this time, in the same format as `createdAfter`. It must be later than `createdAfter`.
          schema:
            type: string
            format: date-time
            example: '2026-10-01T00:00:00Z'
        - name: limit
          in: query
          required: false
          description: Number of builds to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 10
        - name: cursor
          in: query
          required: false
          description: Pagination cursor from `nextCursor` on the previous response. Send the same filters with it.
          schema:
            type: string
            minLength: 1
            maxLength: 512
      responses:
        '200':
          description: Builds retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListEnvironmentBuildsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
    post:
      summary: Start an environment build
      description: Start a build of the environment. Access follows PATCH /v1/environments/{id}, except that a draft build on a team environment needs only read access, and service account API keys and repository-limited tokens are refused. Service account API keys get `403 key_not_supported`. A user-scoped token minted by an API key limited to certain repositories gets `404 environment_not_found` when the environment has no repositories or any repository outside the limit, and `403 key_not_supported` otherwise. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`. Reading the new build right away can briefly return `404`.
      operationId: startEnvironmentBuild
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartEnvironmentBuildRequest'
      responses:
        '202':
          description: Build started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StartEnvironmentBuildResponse'
        '400':
          description: An environment ID that isn't a UUID, a body with fields other than `draft` and `refs` or values of the wrong type, a non-default branch without `draft` set to `true`, a repository that isn't in the environment, two refs for one repository, or a team that requires self-hosted workers (`validation_error`). Duplicate JSON keys return `duplicate_json_key`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, Cloud Agents API access isn't available for your account (`feature_unavailable`), a service account API key (`key_not_supported`), a user-scoped token minted by an API key limited to certain repositories on an environment whose repositories are all inside that limit (`key_not_supported`), or a non-draft build on a team environment when the team lets only admins edit environments (`team_admin_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          description: Too many requests, or too many builds already in progress for this environment (`rate_limit_exceeded`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          description: Cursor couldn't confirm whether the build started (`upstream_error`). Don't retry automatically, because another request can start a second build. Check the environment's builds before deciding what to do.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /v1/environments/{id}/builds/active:
    get:
      summary: Get the active build
      description: Find out what an agent you start on this environment boots from, one of its builds or Cursor's default image. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`.
      operationId: getActiveEnvironmentBuild
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
      responses:
        '200':
          description: Active build retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnvironmentActiveBuild'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/environments/{id}/builds/{buildId}:
    get:
      summary: Get an environment build
      description: Retrieve one of an environment's builds. An environment that doesn't exist or isn't visible to the API key returns `404 environment_not_found`, and a build ID that isn't one of the environment's builds returns `404 build_not_found`.
      operationId: getEnvironmentBuild
      parameters:
        - $ref: '#/components/parameters/EnvironmentId'
        - $ref: '#/components/parameters/EnvironmentBuildId'
      responses:
        '200':
          description: Build retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnvironmentBuild'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/me:
    get:
      summary: API key info
      description: Retrieve information about the API key being used for authentication.
      operationId: getApiKeyInfo
      responses:
        '200':
          description: API key info retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyInfo'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/environments/{id}/secrets:
    get:
      summary: List environment secrets
      description: |
        List an environment's Cloud Agents secrets, one item per version,
        sorted by name. No item includes a value. The list isn't paginated
        yet, so `nextCursor` is always `null`.

        A service account API key can list its team's environments, and
        a user API key or user-scoped token its user's personal
        environments too. An API key limited to certain repositories can
        list only environments whose repositories all sit inside its
        limit. Every other environment returns `404 environment_not_found`.

        See https://cursor.com/docs/cloud-agent/api/endpoints#list-environment-secrets.
      operationId: listEnvironmentSecrets
      parameters:
        - name: id
          in: path
          required: true
          description: Environment ID.
          schema:
            type: string
            format: uuid
            example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
      responses:
        '200':
          description: The environment's secret versions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSecretsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: |
            Plan or role not allowed, the environments API isn't enabled for
            your account (`feature_unavailable`), or a `grok_` API key
            (`key_not_supported`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The environment doesn't exist or your API key can't list its secrets, including an environment outside its repository limit (`environment_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/models:
    get:
      summary: List models
      description: |
        Returns a recommended set of explicit model IDs you can pass
        to the `model.id` field on POST /v1/agents. To use the
        configured default model, omit the `model` field from the
        request body entirely.
      operationId: listModels
      responses:
        '200':
          description: Models retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListModelsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
  /v1/environments/{id}/secrets/{name}:
    parameters:
      - name: id
        in: path
        required: true
        description: Environment ID.
        schema:
          type: string
          format: uuid
          example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
      - name: name
        in: path
        required: true
        description: Secret name, such as `NPM_TOKEN`.
        schema:
          type: string
          example: 'NPM_TOKEN'
    put:
      summary: Set an environment secret
      description: |
        Create an environment secret, rotate its value, or change its type or repositories. With `?id=`, the request changes that version. Without `?id=`, a name with no version gets one (`201`), a name with one version has it changed in place (`200`), and a name with several versions returns `409 secret_name_ambiguous`. A `PUT` never adds a second version to a name that has one, and an omitted `type` or `repos` keeps the current one. Build Secrets can't be set or changed through the API yet. See https://cursor.com/docs/cloud-agent/api/endpoints#set-an-environment-secret.
      operationId: setEnvironmentSecret
      parameters:
        - name: id
          in: query
          required: false
          description: The `id` of the version to change.
          schema:
            type: string
            example: 'secv_3qKx9mT2bV7nR1cW5yZ8aQ'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetSecretRequest'
      responses:
        '200':
          description: The version was changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretVersion'
        '201':
          description: The version was created. `id` and `createdAt` are left out when the new version isn't readable yet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretVersion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, the environments API isn't enabled for your account (`feature_unavailable`), a `grok_` API key (`key_not_supported`), or a team that lets only admins change secrets (`team_admin_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The environment doesn't exist or your API key can't change its secrets, including an environment outside its repository limit (`environment_not_found`), or `?id=` isn't a version of this name here (`secret_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The name has several versions and no `?id=` (`secret_name_ambiguous`, with `versions`), differs from an existing name only in case (`secret_name_conflict`), overlaps another version's repositories (`secret_scope_conflict`), the environment has 1,000 secrets (`secret_limit_reached`), or another request changed the secret at the same moment (`secret_changed`).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SecretNameAmbiguousError'
                  - $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

    delete:
      summary: Delete an environment secret
      description: |
        Delete one version of an environment secret. This action is irreversible. With `?id=`, the request deletes that version. Without `?id=`, a name with one version has it deleted, a name with no version returns `404 secret_not_found`, and a name with several versions returns `409 secret_name_ambiguous` and deletes nothing. `{name}` must match a listed name exactly, letter case included. Every type can be deleted, Build Secrets included. See https://cursor.com/docs/cloud-agent/api/endpoints#delete-an-environment-secret.
      operationId: deleteEnvironmentSecret
      parameters:
        - name: id
          in: query
          required: false
          description: The `id` of the version to delete.
          schema:
            type: string
            example: 'secv_3qKx9mT2bV7nR1cW5yZ8aQ'
      responses:
        '200':
          description: The version was deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteSecretResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, the environments API isn't enabled for your account (`feature_unavailable`), a `grok_` API key (`key_not_supported`), or a team that lets only admins change secrets (`team_admin_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The environment doesn't exist or your API key can't change its secrets, including an environment outside its repository limit (`environment_not_found`), or the name or `?id=` isn't a version here (`secret_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The name has several versions and no `?id=` (`secret_name_ambiguous`, with `versions`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretNameAmbiguousError'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
  /v1/repositories:
    get:
      summary: List GitHub repositories
      description: |
        List GitHub repositories accessible to the authenticated user
        through Cursor's GitHub App installation. This endpoint has
        very strict rate limits (1 request per user per minute, 30
        per user per hour) and can take tens of seconds to respond
        for users with access to many repositories. Cache responses
        aggressively and handle this information not being available
        gracefully.
      operationId: listRepositories
      responses:
        '200':
          description: Repositories retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListRepositoriesResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
  /v1/team/secrets/{name}:
    parameters:
      - name: name
        in: path
        required: true
        description: Secret name, such as `NPM_TOKEN`.
        schema:
          type: string
          example: 'NPM_TOKEN'
    put:
      summary: Set a team secret
      description: |
        Create a secret for the team the API key works in, rotate its value, or change its type or repositories. With `?id=`, the request changes that version. Without `?id=`, a name with no version gets one (`201`), a name with one version has it changed in place (`200`), and a name with several versions returns `409 secret_name_ambiguous`. A `PUT` never adds a second version to a name that has one, and an omitted `type` or `repos` keeps the current one. Build Secrets can't be set or changed through the API yet. See https://cursor.com/docs/cloud-agent/api/endpoints#set-a-team-secret.
      operationId: setTeamSecret
      parameters:
        - name: id
          in: query
          required: false
          description: The `id` of the version to change, from the team's secrets list.
          schema:
            type: string
            example: 'secv_Ub4rJ7nD2kX9qM5wL1sE8Q'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetSecretRequest'
      responses:
        '200':
          description: The version was changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretVersion'
        '201':
          description: The version was created. `id` and `createdAt` are left out when the new version isn't readable yet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretVersion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, the environments API isn't enabled for your account (`feature_unavailable`), a `grok_` API key (`key_not_supported`), an API key limited to certain repositories (`repository_access`), a team that lets only admins change secrets (`team_admin_required`), or an API key that isn't working in a team or whose user isn't a team member (`team_membership_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: '`?id=` isn''t a version of this name in the team (`secret_not_found`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The name has several versions and no `?id=` (`secret_name_ambiguous`, with `versions`), differs from an existing name only in case (`secret_name_conflict`), overlaps another version's repositories (`secret_scope_conflict`), the team has 1,000 secrets (`secret_limit_reached`), or another request changed the secret at the same moment (`secret_changed`).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SecretNameAmbiguousError'
                  - $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

    delete:
      summary: Delete a team secret
      description: |
        Delete one version of a secret from the team the API key works in. This action is irreversible. With `?id=`, the request deletes that version. Without `?id=`, a name with one version has it deleted, a name with no version returns `404 secret_not_found`, and a name with several versions returns `409 secret_name_ambiguous` and deletes nothing. `{name}` must match a listed name exactly, letter case included. Every type can be deleted, Build Secrets included. See https://cursor.com/docs/cloud-agent/api/endpoints#delete-a-team-secret.
      operationId: deleteTeamSecret
      parameters:
        - name: id
          in: query
          required: false
          description: The `id` of the version to delete, from the team's secrets list.
          schema:
            type: string
            example: 'secv_Ub4rJ7nD2kX9qM5wL1sE8Q'
      responses:
        '200':
          description: The version was deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteSecretResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, the environments API isn't enabled for your account (`feature_unavailable`), a `grok_` API key (`key_not_supported`), an API key limited to certain repositories (`repository_access`), a team that lets only admins change secrets (`team_admin_required`), or an API key that isn't working in a team or whose user isn't a team member (`team_membership_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The name or `?id=` isn't a version in the team (`secret_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The name has several versions and no `?id=` (`secret_name_ambiguous`, with `versions`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretNameAmbiguousError'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
  /v1/me/secrets/{name}:
    parameters:
      - name: name
        in: path
        required: true
        description: Secret name, such as `NPM_TOKEN`.
        schema:
          type: string
          example: 'NPM_TOKEN'
    put:
      summary: Set a personal secret
      description: |
        Create a personal secret for the user the API key acts for, rotate its value, or change its type or repositories. With `?id=`, the request changes that version. Without `?id=`, a name with no version gets one (`201`), a name with one version has it changed in place (`200`), and a name with several versions returns `409 secret_name_ambiguous`. A `PUT` never adds a second version to a name that has one, and an omitted `type` or `repos` keeps the current one. Build Secrets can't be set or changed; either returns `400 validation_error`. `DELETE` can remove one. See https://cursor.com/docs/cloud-agent/api/endpoints#set-a-personal-secret.
      operationId: setPersonalSecret
      parameters:
        - name: id
          in: query
          required: false
          description: The `id` of the version to change, from the user's personal secrets list.
          schema:
            type: string
            example: 'secv_Pk6nV3yH8rT1wQ4zM9cX2b'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetSecretRequest'
      responses:
        '200':
          description: The version was changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretVersion'
        '201':
          description: The version was created. It can leave out `id` and `createdAt`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretVersion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, Cloud Agents API access isn't available for your account (`feature_unavailable`), a `grok_` API key (`key_not_supported`), an API key that doesn't act for a user, such as a service account API key (`user_required`), a user-scoped token minted by an API key limited to certain repositories (`repository_access`), or a team that has turned off personal secrets (`personal_secrets_disabled`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: '`?id=` isn''t a version of this name among the user''s personal secrets (`secret_not_found`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The name has several versions and no `?id=` (`secret_name_ambiguous`, with `versions`), differs from an existing name only in case (`secret_name_conflict`), overlaps another version's repositories (`secret_scope_conflict`), the user has 1,000 personal secrets (`secret_limit_reached`), or another request changed the secret at the same moment (`secret_changed`).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SecretNameAmbiguousError'
                  - $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

    delete:
      summary: Delete a personal secret
      description: |
        Delete one version of a personal secret of the user the API key acts for. This action is irreversible. With `?id=`, the request deletes that version. Without `?id=`, a name with one version has it deleted, a name with no version returns `404 secret_not_found`, and a name with several versions returns `409 secret_name_ambiguous` and deletes nothing. `{name}` must match a listed name exactly, letter case included. See https://cursor.com/docs/cloud-agent/api/endpoints#delete-a-personal-secret.
      operationId: deletePersonalSecret
      parameters:
        - name: id
          in: query
          required: false
          description: The `id` of the version to delete, from the user's personal secrets list.
          schema:
            type: string
            example: 'secv_Pk6nV3yH8rT1wQ4zM9cX2b'
      responses:
        '200':
          description: The version was deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteSecretResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Plan or role not allowed, Cloud Agents API access isn't available for your account (`feature_unavailable`), a `grok_` API key (`key_not_supported`), an API key that doesn't act for a user, such as a service account API key (`user_required`), or a user-scoped token minted by an API key limited to certain repositories (`repository_access`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The name or `?id=` isn't a version among the user's personal secrets (`secret_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The name has several versions and no `?id=` (`secret_name_ambiguous`, with `versions`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretNameAmbiguousError'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
  /v1/sub-tokens:
    post:
      summary: Create A User-Scoped Worker Token
      description: |
        Create a one-hour user-scoped token for a My Machines 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.
      operationId: createSubToken
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSubTokenRequest'
            examples:
              byEmail:
                summary: Identify the user by email
                value:
                  forUserEmail: 'alice@company.com'
              byUserId:
                summary: Identify the user by Cursor user ID
                value:
                  forUserId: 42
      responses:
        '200':
          description: User-scoped token created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateSubTokenResponse'
              example:
                accessToken: 'eyJ...'
                expiresAt: '2026-04-24T19:00:00.000Z'
                userId: 42
                teamId: 456
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/team/secrets:
    get:
      summary: List team secrets
      description: |
        List the Cloud Agents secrets of the team the API key works in, one
        item per version, sorted by name. No item includes a value. The
        list isn't paginated yet, so `nextCursor` is always `null`.

        Any team member can list, as can the team's service account API
        keys. An API key limited to certain repositories gets
        `403 repository_access`, because team secrets reach every
        repository.

        See https://cursor.com/docs/cloud-agent/api/endpoints#list-team-secrets.
      operationId: listTeamSecrets
      responses:
        '200':
          description: The team's secret versions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSecretsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: |
            Plan or role not allowed, the environments API isn't enabled for
            your account (`feature_unavailable`), a `grok_` API key
            (`key_not_supported`), an API key limited to certain
            repositories (`repository_access`), or an API key that isn't
            working in a team or whose user isn't a team member
            (`team_membership_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/secrets:
    get:
      summary: List secrets
      description: |
        List every Cloud Agents secret the API key can list, one item per
        version, with the owner that holds it. No item includes a value.

        Without `scope` or `environmentId`, the list includes the team's
        secrets and the user's personal secrets for an API key with no
        repository limit, and the secrets of the environments the key can
        list. A team admin using their own user API key without `repo` also
        gets the other members' personal secrets and their personal
        environments' secrets, with their `repos`.

        Keep paging until `nextCursor` is `null`, and send the same filters
        with each `cursor`.

        See https://cursor.com/docs/cloud-agent/api/endpoints#list-secrets.
      operationId: listSecrets
      parameters:
        - name: scope
          in: query
          required: false
          description: |
            `team` lists only the team's secrets, `user` only the user's
            personal secrets, and `environment` only environment secrets.
            `members` lists the user's personal secrets and, for an explicit
            team admin using their own user API key or session, every other
            current member's personal secrets after them, but none of their
            personal environments' secrets. For everyone else it returns the
            same response or refusal as `user`.
          schema:
            type: string
            enum:
              - team
              - user
              - members
              - environment
        - name: environmentId
          in: query
          required: false
          description: |
            List only this environment's secrets. Combining it with
            `scope=team`, `scope=user`, or `scope=members` returns
            `400 validation_error`.
          schema:
            type: string
            format: uuid
            example: '8f14e45f-ceea-4e6b-9c3a-1d2e3f4a5b6c'
        - name: name
          in: query
          required: false
          description: Only versions with this name, ignoring case.
          schema:
            type: string
            minLength: 1
            example: 'NPM_TOKEN'
        - name: repo
          in: query
          required: false
          description: |
            Only the versions an agent on this repository gets: versions for
            that repository and versions for every repository. Combining it
            with `scope=members` returns `400 validation_error`.
          schema:
            type: string
            example: 'github.com/acme/api'
        - name: limit
          in: query
          required: false
          description: Maximum items per page.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
        - name: cursor
          in: query
          required: false
          description: '`nextCursor` from the previous page.'
          schema:
            type: string
            minLength: 1
      responses:
        '200':
          description: A page of secret versions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSecretInventoryResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: |
            Plan or role not allowed, the environments API isn't enabled for
            your account (`feature_unavailable`), or a `grok_` API key
            (`key_not_supported`). With `scope=team`, an API key limited to
            certain repositories (`repository_access`) or one that isn't
            working in a team or whose user isn't a team member
            (`team_membership_required`). With `scope=user` or
            `scope=members`, an API key limited to certain repositories
            (`repository_access`) or one that doesn't act for a user
            (`user_required`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: '`environmentId` names an environment that doesn''t exist or that your API key can''t list (`environment_not_found`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
