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.
  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.
          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', 'FINISHED', 'ERROR', 'CANCELLED', 'EXPIRED']
          description: Current run status.
        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: 20
          description: 'Repository configuration. Mutually exclusive with a named cloud environment. Omit both `repos` and `env` (or pass `repos: []`) to start a no-repo agent.'
          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:
          type: object
          maxProperties: 50
          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 must be non-empty,
            255 bytes or less, and cannot start with `CURSOR_`. Values
            must be non-empty and 4096 bytes or less. 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.
          additionalProperties:
            type: string
            minLength: 1
            maxLength: 4096
        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.

    CreateRunRequest:
      type: object
      required:
        - prompt
      properties:
        prompt:
          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.
        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'
        mode:
          $ref: '#/components/schemas/AgentMode'

    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'

    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'

    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'

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

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

    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]

    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

    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`,
                `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`, `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`.

  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'

  responses:
    BadRequest:
      description: Validation error or malformed request body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Invalid or missing API key.
      content:
        application/json:
          schema:
            $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: Agent or run not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Resource state conflict (`agent_busy`, `agent_archived`, `agent_id_conflict`, or `run_not_cancellable`).
      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: Create a run
      description: |
        Send a follow-up prompt to an existing active agent. The new
        run uses the agent's current conversation and workspace state.
        Only one run can be active per agent at a time.
      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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateRunResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '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'
    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/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/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/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/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'
