> ## Documentation Index
> Fetch the complete documentation index at: https://www.truefoundry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create or update a cluster

> Create a new cluster or update an existing one using the provided `ClusterManifest`. Matching is by `name` — if a cluster with the same name exists it is updated, otherwise a new one is created.



## OpenAPI

````yaml /openapi.json put /api/svc/v1/clusters
openapi: 3.1.0
info:
  title: TrueFoundry API
  description: API for TrueFoundry
  version: 0.1.0
  contact: {}
servers:
  - url: https://{controlPlaneURL}
    variables:
      controlPlaneURL:
        default: app.truefoundry.com
        description: Control Plane URL
security: []
tags:
  - name: Agent
  - name: Agent Skills
  - name: Applications
  - name: Metrics
  - name: Apply
  - name: Artifacts
  - name: Audit Logs
  - name: Clusters
  - name: Jobs
  - name: Logs
  - name: MCP Servers V2
  - name: MLRepos
  - name: Model Deployments
  - name: Models
  - name: Personal Access Tokens
  - name: Prompts
  - name: Provider Integrations
  - name: SCIM v2
  - name: Secret Groups
  - name: Secrets
  - name: Teams
  - name: Traces
  - name: Users
  - name: Virtual Accounts
  - name: Role Bindings
  - name: Workspaces
paths:
  /api/svc/v1/clusters:
    put:
      tags:
        - Clusters
      summary: Create or update a cluster
      description: >-
        Create a new cluster or update an existing one using the provided
        `ClusterManifest`. Matching is by `name` — if a cluster with the same
        name exists it is updated, otherwise a new one is created.
      operationId: Cluster.createOrUpdate
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrUpdateClusterRequest'
      responses:
        '200':
          description: The created or updated cluster.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetClusterResponse'
        '401':
          description: 'Error: Unauthorized'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
        '409':
          description: >
            Conflict. This can happen due to: 

            1. Immutable field cluster_type cannot be updated for an existing
            cluster 

            2. Cloud provider cannot be assigned to a cluster integration with
            different provider 

            3. Cluster integration is already used in another cluster 
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
        '422':
          description: >
            Unprocessable entity. This can happen due to: 

            1. Invalid manifest schema 

            2. No collaborators or no admin in collaborators 

            3. No environment tags or invalid environment tags provided 

            4. Nodepool names should be unique 

            5. Nodepools should not be passed when cluster_integration_fqn is
            defined 

            6. Generic clusters should not have supported nodepools directly 

            7. Default registry not found or not accessible 

            8. Cluster integration not found or not accessible 
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
      security:
        - jwt: []
components:
  schemas:
    CreateOrUpdateClusterRequest:
      type: object
      properties:
        manifest:
          oneOf:
            - $ref: '#/components/schemas/ClusterManifest'
          description: Full cluster manifest.
        dryRun:
          type: boolean
          default: false
          description: When true, validates the request without persisting changes.
          nullable: true
      required:
        - manifest
      title: CreateOrUpdateClusterRequest
      x-fern-type-name: CreateOrUpdateClusterRequest
    GetClusterResponse:
      type: object
      properties:
        data:
          description: The cluster object.
          allOf:
            - $ref: '#/components/schemas/Cluster'
      required:
        - data
      title: GetClusterResponse
      x-fern-type-name: GetClusterResponse
    HttpError:
      type: object
      properties:
        statusCode:
          type: integer
          description: HTTP Status Code
        message:
          type: string
          description: Error Message
        code:
          oneOf:
            - type: integer
            - type: string
          description: Error code
          nullable: true
        details:
          type: array
          description: Error details
          items:
            type: object
          nullable: true
      required:
        - statusCode
        - message
      title: HttpError
      x-fern-type-name: HttpError
    ClusterManifest:
      type: object
      required:
        - type
        - name
        - cluster_type
        - environment_names
        - collaborators
      properties:
        type:
          description: +value=cluster
          type: string
          enum:
            - cluster
        name:
          description: >-
            Name - 3 to 35 lower case characters long alphanumeric word, may
            contain - in between, cannot start with a number
          type: string
          pattern: ^[a-z][a-z0-9\-]{1,33}[a-z0-9]$
        cluster_type:
          description: The cluster type of this cluster
          type: string
          enum:
            - aws-eks
            - gcp-gke-standard
            - azure-aks
            - generic
            - civo-talos
        environment_names:
          description: >-
            Tag the environment like dev, staging or production. You will need
            to [create
            environments](https://docs.truefoundry.com/docs/key-concepts#creating-environments)
            if you don't have already.
          type: array
          items:
            type: string
        base_domains:
          description: >-
            One or more base URLs, which can be either a wildcard domain
            (resulting in app URLs like
            `<app-name>-<workspace-name>.<base-domain-URL>`) or a non-wildcard
            domain (resulting in app URLs like
            `<base-domain-URL>/<app-name>-<workspace-name>`)

            > Read more about routing
            [here](https://docs.truefoundry.com/docs/routing) and about 'A'
            record and domain mapping
            [here](https://docs.truefoundry.com/docs/setting-up-domain)
          type: array
          items:
            type: string
            pattern: >-
              ^((((\*|[a-zA-Z0-9\-]{1,63})\.)([a-zA-Z0-9\-]{1,63}\.)*([A-Za-z]{1,63}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))$
        monitoring:
          description: Monitoring
          type: object
          properties:
            loki_url:
              description: Cluster Loki URL
              type: string
            victoria_logs_url:
              description: Cluster VictoriaLogs URL
              type: string
            prometheus_url:
              description: Cluster Prometheus URL
              type: string
            kubecost_url:
              description: Cluster Kubecost URL
              type: string
        default_registry_fqn:
          description: Cluster Default Registry
          type: string
        workbench_config:
          description: Workbench Config
          type: object
          properties:
            notebook_config:
              $ref: '#/components/schemas/NotebookConfig'
            ssh_server_config:
              $ref: '#/components/schemas/SSHServerConfig'
            default_storage_class:
              description: The default storage class for the home directory of workbench
              type: string
              pattern: ^[^\s]*$
        spark_config:
          $ref: '#/components/schemas/SparkConfig'
        ingress_controller_config:
          $ref: '#/components/schemas/IngressControllerConfig'
        cluster_integration_fqn:
          description: Cluster Integration FQN
          type: string
        workflow_storage_integration_fqn:
          description: Workflow Storage Integration
          type: string
        supported_nodepools:
          description: >-
            Add nodepools that are already created in your cluster.

            When deploying, applications can choose to schedule from these
            nodepools.
          type: array
          items:
            $ref: '#/components/schemas/Nodepool'
        node_label_keys:
          description: >-
            The node label keys that this cluster supports.

            Note: You will additionally need to add `truefoundry.com/gpu_type`
            label for GPU-supported node pools.

            For more information, check out [this
            documentation](https://docs.truefoundry.com/docs/generic-control-plane#configuring-node-pools-for-truefoundry).
          type: object
          required:
            - nodepool_selector_label
          properties:
            nodepool_selector_label:
              description: The nodepool selector label that this cluster supports
              type: string
        collaborators:
          description: Collaborators who can access this cluster
          type: array
          items:
            $ref: '#/components/schemas/Collaborator'
        ownedBy:
          $ref: '#/components/schemas/OwnedBy'
      title: ClusterManifest
      x-fern-type-name: ClusterManifest
    Cluster:
      type: object
      properties:
        id:
          type: string
          description: System-generated cluster ID.
          example: jqfwg345gi25n5ju2yz5iz6m
        fqn:
          type: string
          description: Human-readable Fully Qualified Name of the cluster.
        manifest:
          oneOf:
            - $ref: '#/components/schemas/ClusterManifest'
        tenantName:
          type: string
        accountId:
          type: string
          nullable: false
        createdBySubject:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Subject'
        createdAt:
          format: date-time
          type: string
        updatedAt:
          format: date-time
          type: string
        createdBy:
          type: string
          nullable: true
      required:
        - id
        - fqn
        - manifest
        - tenantName
        - accountId
        - createdAt
        - updatedAt
      title: Cluster
      x-fern-type-name: Cluster
    NotebookConfig:
      type: object
      required:
        - base_domain
      properties:
        base_domain:
          description: >-
            The base domain for the cluster with which you can access your
            Notebooks
          type: string
          pattern: ^[^\s]*$
      title: NotebookConfig
      x-fern-type-name: NotebookConfig
    SSHServerConfig:
      type: object
      required:
        - base_domain
        - port
      properties:
        base_domain:
          description: >-
            The base domain for the cluster with which you can access your SSH
            containers
          type: string
          pattern: ^[^\s]*$
        port:
          description: >-
            The port for the cluster with which you can access your SSH
            containers
          type: number
      title: SSHServerConfig
      x-fern-type-name: SSHServerConfig
    SparkConfig:
      type: object
      required:
        - ui_base_domain
      properties:
        ui_base_domain:
          description: >-
            The base domain for the cluster with which you can access your Spark
            UI
          type: string
          pattern: ^[^\s]*$
      title: SparkConfig
      x-fern-type-name: SparkConfig
    IngressControllerConfig:
      type: object
      required:
        - ingress_class_name
      properties:
        ingress_class_name:
          description: Ingress Class Name
          type: string
          default: nginx
        tls_enabled:
          description: >-
            Whether TLS is managed by the ingress controller. If enabled, the
            ingress object will have TLS configuration.
          type: boolean
          default: false
      title: IngressControllerConfig
      x-fern-type-name: IngressControllerConfig
    Nodepool:
      description: >-
        The nodepools that are already created in your cluster. This will be
        used to schedule your workloads on particular nodepools.
      type: object
      required:
        - name
      properties:
        name:
          type: string
        description:
          type: string
      title: Nodepool
      x-fern-type-name: Nodepool
    Collaborator:
      type: object
      required:
        - subject
        - role_id
      properties:
        subject:
          description: 'Fully Qualified Name of the subject. eg: user:email or team:teamname'
          type: string
        role_id:
          description: Role ID for the resource
          type: string
      title: Collaborator
      x-fern-type-name: Collaborator
    OwnedBy:
      description: Names of the owners that own this resource
      type: object
      required:
        - account
      properties:
        account:
          description: The name of the account that owns this resource
          type: string
      title: OwnedBy
      x-fern-type-name: OwnedBy
    Subject:
      type: object
      properties:
        subjectId:
          type: string
          description: Subject ID
        subjectType:
          description: Subject type
          allOf:
            - $ref: '#/components/schemas/SubjectType'
        subjectSlug:
          type: string
          description: Subject slug
          nullable: true
        subjectDisplayName:
          type: string
          description: Subject display name
          nullable: true
        subjectPatName:
          type: string
          description: Subject PAT name
          nullable: true
        subjectControllerName:
          type: string
          nullable: true
        subjectExternalIdentitySlug:
          type: string
          description: External identity slug (external_identity_id:sub:email)
          nullable: true
      required:
        - subjectId
        - subjectType
      title: Subject
      x-fern-type-name: Subject
    SubjectType:
      type: string
      enum:
        - user
        - team
        - serviceaccount
        - virtualaccount
        - external-identity
        - agent-identity
        - role
      description: >-
        Type of the authenticated subject. "user" for human users,
        "serviceaccount" (also known as virtual account) for programmatic
        access.
      title: SubjectType
      x-fern-type-name: SubjectType
  securitySchemes:
    jwt:
      type: http
      scheme: bearer
      bearerFormat: JWT

````