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

# Create a cluster

> Launches a Kubernetes or Slurm cluster on capacity your organization already holds; it does not purchase GPUs. List the hosts to use in node_ids. Each must be in bare-metal status, not in another cluster, and on an active reservation your organization owns; hosts can come from more than one such reservation. If node_ids and virtual_machine_ids are both omitted or empty, every bare-metal host on reservation_id is used. Before a host joins, Ornn prepares it - running processes are stopped, the tenant home directory is wiped, and any VM on that host is removed - so save its data first.

Your organization can run one cluster of each kind at a time, and cannot run Kubernetes and Slurm clusters at the same time. A cluster counts until its teardown finishes. A repeat request for a reservation whose cluster is active, or provisioning with workers attached, returns that cluster with 202 and changes nothing, even if the node list differs; change membership with the worker operations. A request after a failed launch on the same reservation relaunches it under the same id. Do not create while a teardown is in progress.

A 202 response means the launch was accepted, not that the cluster is ready. Poll listClusters until state is active or failed, then call getClusterAccess. This route does not read an Idempotency-Key header; after a timeout or 5xx, list clusters and look for the reservation before sending the request again. Unknown body fields are rejected. Malformed JSON, unknown fields, or a missing Content-Type return 400, 422, or 415 with a plain-text body.

For the full lifecycle with polling and retry guidance, follow [Automate managed Kubernetes with the Ornn API](/guides/kubernetes-api) or [Launch and manage Slurm through the API](/guides/slurm-access#launch-and-manage-through-the-api).

CLI equivalent, after `ornn login`:

```bash theme={null}
ornn launch --mode kubernetes --reservation RESERVATION_ID --nodes 1 \
  --machines NODE_ID --network public
```


## OpenAPI

````yaml openapi.yaml POST /v1/orchestrator/controllers
openapi: 3.1.0
info:
  title: Ornn compute API
  version: 1.0.0
  description: >-
    Customer HTTP API for Ornn GPU capacity. It covers reserved capacity and
    nodes, VM and Bare Metal access, Kubernetes and Slurm clusters, SSH keys,
    storage volumes and GitHub repositories, private networks, monitoring,
    buying and selling capacity (Reserve, Market, Spot, and Relist), and
    billing. API keys are scoped to one organization and act with their
    creator's access there; account, team, and API-key management stay in the
    console. Most operations require an approved organization. See
    https://docs.ornn.com/api-keys to create a key and
    https://docs.ornn.com/guides/kubernetes-api for an end-to-end Kubernetes
    integration. Examples use fictional IDs and credentials. The info.version
    field identifies the contract revision, not a shared API path version.
  contact:
    email: support@ornn.com
servers:
  - url: https://api.ornn.com
    description: Production
security:
  - OrnnApiKey: []
tags:
  - name: Authentication
  - name: Reservations
  - name: GPU nodes
  - name: Clusters
  - name: Workers
  - name: Virtual machines
    description: >-
      Choose a VM disk, launch VM access on a reservation, and read each VM's
      status, launch progress, and SSH connection details.
  - name: Bare Metal
    description: >-
      Launch Bare Metal access on a reservation, read a host's readiness and SSH
      connection details, and reboot or hard reset it.
  - name: SSH keys
    description: >-
      Register public keys for your organization, choose which keys a VM or Bare
      Metal reservation uses, and queue key delivery to machines. Slurm clusters
      take organization key IDs at launch. Kubernetes API access does not use
      SSH keys.
  - name: Reserve
    description: >-
      Browse reserved-capacity listings and their terms, and post, cancel, or
      accept offers. Reserve listings are visible to approved organizations.
  - name: Market
    description: >-
      Browse relisted capacity and buy windows at the asking price, paid up
      front. Open to every member of your organization.
  - name: Spot
    description: >-
      Hourly order books for VMs with 1, 2, 4, or 8 GPUs on one node: read
      books, trades, and quotes, place and cancel bids, and follow fills.
  - name: Relist
    description: >-
      Sell whole nodes from a reservation you hold at your asking price, and
      manage those listings.
  - name: Storage
    description: >-
      Managed volumes, their files, and GitHub repository pulls. Volumes belong
      to the API key's creator in the key's organization.
  - name: Networks
    description: >-
      Organization private networks and the WireGuard configs you use to reach
      private machines and clusters.
  - name: Monitoring
    description: >-
      Machine telemetry and console logs for capacity your organization holds.
      Reads are limited to your reservation window.
  - name: Billing
    description: >-
      Invoices, billing summary, usage cost, Ornn credits, and account
      statements. Saving a card and paying invoices stay in the console.
externalDocs:
  description: REST integration walkthrough
  url: >-
    https://docs.ornn.com/guides/kubernetes-access#provision-and-manage-through-rest
paths:
  /v1/orchestrator/controllers:
    post:
      tags:
        - Clusters
      summary: Create a cluster
      description: >-
        Launches a Kubernetes or Slurm cluster on capacity your organization
        already holds; it does not purchase GPUs. List the hosts to use in
        node_ids. Each must be in bare-metal status, not in another cluster, and
        on an active reservation your organization owns; hosts can come from
        more than one such reservation. If node_ids and virtual_machine_ids are
        both omitted or empty, every bare-metal host on reservation_id is used.
        Before a host joins, Ornn prepares it - running processes are stopped,
        the tenant home directory is wiped, and any VM on that host is removed -
        so save its data first.


        Your organization can run one cluster of each kind at a time, and cannot
        run Kubernetes and Slurm clusters at the same time. A cluster counts
        until its teardown finishes. A repeat request for a reservation whose
        cluster is active, or provisioning with workers attached, returns that
        cluster with 202 and changes nothing, even if the node list differs;
        change membership with the worker operations. A request after a failed
        launch on the same reservation relaunches it under the same id. Do not
        create while a teardown is in progress.


        A 202 response means the launch was accepted, not that the cluster is
        ready. Poll listClusters until state is active or failed, then call
        getClusterAccess. This route does not read an Idempotency-Key header;
        after a timeout or 5xx, list clusters and look for the reservation
        before sending the request again. Unknown body fields are rejected.
        Malformed JSON, unknown fields, or a missing Content-Type return 400,
        422, or 415 with a plain-text body.
      operationId: createCluster
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCluster'
            examples:
              kubernetes:
                summary: Kubernetes on one selected host
                value:
                  kind: kubernetes
                  reservation_id: 11111111-1111-4111-8111-111111111111
                  network_mode: public
                  node_ids:
                    - 33333333-3333-4333-8333-333333333333
              slurm:
                summary: Slurm on two selected hosts with one SSH key
                value:
                  kind: slurm
                  reservation_id: 11111111-1111-4111-8111-111111111111
                  network_mode: public
                  node_ids:
                    - 33333333-3333-4333-8333-333333333333
                    - 77777777-7777-4777-8777-777777777777
                  ssh_key_ids:
                    - 88888888-8888-4888-8888-888888888888
      responses:
        '202':
          description: >-
            Launch accepted. node_count and gpu_count count workers attached so
            far and are usually 0 in this response. Poll listClusters for
            progress.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClusterAccepted'
              example:
                id: 44444444-4444-4444-8444-444444444444
                kind: kubernetes
                organization_id: 22222222-2222-4222-8222-222222222222
                access_mode: kubernetes
                state: provisioning
                network_mode: public
                endpoint: null
                credential_state: pending
                namespace: k8s-22222222-2222-4222-8222-222222222222
                node_count: 0
                gpu_count: 0
                progress: null
                created_at: '2026-10-14T12:00:00Z'
                updated_at: '2026-10-14T12:00:00Z'
        '400':
          description: The request names an unsupported cluster kind or repeats a host.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                unsupportedKind:
                  summary: Unsupported cluster kind
                  value:
                    detail:
                      code: unsupported_controller_kind
                      message: >-
                        That cluster type is not supported. Choose Kubernetes or
                        Slurm.
                duplicateNode:
                  summary: The same host is listed twice
                  value:
                    detail:
                      code: cluster_nodes_duplicate
                      message: >-
                        Each node can only be selected once. Review the node
                        selection and try again.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: >-
            The reservation, a listed host, or a listed VM is not visible to
            your organization. A supplier's view of a sale does not grant launch
            rights.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                reservation:
                  summary: Reservation not owned or not found
                  value:
                    detail:
                      code: reservation_not_found
                      message: Ornn could not find that reservation.
                node:
                  summary: A listed host is not owned or does not exist
                  value:
                    detail:
                      code: node_not_found
                      message: Ornn could not find that node in this cluster.
                virtualMachine:
                  summary: A listed VM is not owned, does not exist, or is offline
                  value:
                    detail:
                      code: virtual_machine_not_found
                      message: Ornn could not find that virtual machine.
        '409':
          description: >-
            A lifecycle or capacity conflict prevents launch. Read detail.code
            and current state before retrying. launch_node_offline names the
            host and its last heartbeat at the top level.
            cluster_access_mode_conflict adds live_mode, the kind of cluster
            your organization already runs.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                otherKindRunning:
                  summary: A cluster of the other kind is still live
                  value:
                    detail:
                      code: cluster_access_mode_conflict
                      message: >-
                        This reservation already has a live cluster in another
                        access mode. Tear it down before launching a different
                        cluster type.
                    live_mode: slurm
                otherClusterRunning:
                  summary: >-
                    Your organization already runs a Kubernetes cluster on
                    another reservation
                  value:
                    detail:
                      code: kubernetes_cluster_ambiguous_group
                      message: >-
                        These nodes belong to more than one Kubernetes cluster.
                        Choose nodes from one cluster.
                nodeOffline:
                  summary: A selected host has not sent a heartbeat recently
                  value:
                    detail:
                      code: launch_node_offline
                      message: >-
                        That node is offline. Power it on and try the launch
                        again.
                    node_id: 33333333-3333-4333-8333-333333333333
                    last_heartbeat_at: '2026-10-14T11:40:00+00:00'
                    heartbeat_max_age_seconds: 180
                nodesUnavailable:
                  summary: A selected host is not in bare-metal status
                  value:
                    detail:
                      code: cluster_nodes_not_available
                      message: >-
                        One or more selected nodes are no longer available.
                        Refresh the node list and try again.
                reservationEnded:
                  summary: >-
                    The reservation ended, was cancelled, or has a pending
                    change
                  value:
                    detail:
                      code: reservation_not_launchable
                      message: This reservation cannot launch in its current state.
                sameHost:
                  summary: A host and a VM on that host were both listed
                  value:
                    detail:
                      code: node_virtual_machine_same_host
                      message: Choose that node or its virtual machine, not both.
                slurmKeyRequired:
                  summary: Slurm launch with no active organization SSH key
                  value:
                    detail:
                      code: slurm_ssh_key_required
                      message: >-
                        Add an SSH key to your account first. Slurm logins use
                        your saved account SSH keys.
                slurmNodeCount:
                  summary: Slurm node_count does not match the hosts that resolved
                  value:
                    error: cluster_nodes_requested_unavailable
                    detail: cluster_nodes_requested_unavailable
                    requested: 2
                    available: 1
        '422':
          description: >-
            Invalid cluster configuration. The example uses an unsupported
            network mode.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                detail:
                  code: invalid_network_mode
                  message: Choose Public or Private VPN for the cluster network.
        default:
          $ref: '#/components/responses/Error'
components:
  schemas:
    CreateCluster:
      type: object
      required:
        - kind
        - reservation_id
      properties:
        kind:
          type: string
          enum:
            - kubernetes
            - slurm
          description: The cluster type to launch.
        reservation_id:
          type: string
          format: uuid
          description: >-
            An active reservation your organization holds. A repeat request for
            the same reservation returns the same cluster. Use reservationId
            from the reservation list, not a listing ID.
        network_mode:
          type: string
          enum:
            - public
            - private
          default: public
          description: >-
            public exposes the Kubernetes API or Slurm SSH login on the
            internet, with authentication. private requires a WireGuard
            connection to your organization's private network.
        network_id:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            An existing organization network for private access. Used only when
            network_mode is private. Omit it to use the shared default network;
            this does not create a network.
        node_ids:
          type: array
          items:
            type: string
            format: uuid
          description: >-
            Host IDs (node_id from the reservation node list), not GPU IDs. Each
            host must be in bare-metal status, not in another cluster, and on an
            active reservation your organization owns. Ornn prepares each host
            before it joins, which stops its processes, wipes the tenant home
            directory, and removes any VM on it. If this and virtual_machine_ids
            are both omitted or empty, every bare-metal host on reservation_id
            is used.
        virtual_machine_ids:
          type: array
          items:
            type: string
            format: uuid
          description: >-
            Existing VMs on reservations your organization owns to use as
            workers. A VM must not be deleted, destroyed, or offline. Do not
            list a VM and its host in node_ids in the same request.
        node_count:
          type:
            - integer
            - 'null'
          description: >-
            Optional expected host count; it never selects or limits hosts.
            Kubernetes ignores it. Slurm rejects the launch with 409
            cluster_nodes_requested_unavailable when it differs from the number
            of hosts that resolved. Omit it, or send exactly the number of hosts
            you list.
        ssh_key_ids:
          type: array
          items:
            type: string
            format: uuid
          description: >-
            Slurm only. Organization SSH key IDs (ssh_keys[].id from GET
            /v1/organizations/{organization_id}/ssh-keys) to authorize on the
            login node. Omit to authorize every active key in your organization;
            with no active key, Slurm launch returns 409 slurm_ssh_key_required.
            Kubernetes ignores this field.
        cluster_name:
          type:
            - string
            - 'null'
          deprecated: true
          description: Accepted for compatibility and ignored.
      additionalProperties: false
    ClusterAccepted:
      type: object
      required:
        - id
        - state
      properties:
        id:
          type: string
          format: uuid
        kind:
          type: string
        organization_id:
          type:
            - string
            - 'null'
          format: uuid
        access_mode:
          type: string
        state:
          type: string
        network_mode:
          type: string
        endpoint:
          type:
            - string
            - 'null'
        credential_state:
          type: string
        namespace:
          type:
            - string
            - 'null'
          description: The namespace Ornn configures for your workloads.
        node_count:
          type: integer
          description: >-
            Workers attached when this response was built; usually 0 right after
            a launch.
        gpu_count:
          type: integer
          description: GPUs on the workers counted in node_count.
        progress:
          anyOf:
            - $ref: '#/components/schemas/Progress'
            - type: 'null'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    Error:
      type: object
      properties:
        code:
          type: string
        detail:
          oneOf:
            - type: string
            - type: object
              required:
                - code
                - message
              properties:
                code:
                  type: string
                message:
                  type: string
    Progress:
      type: object
      description: >-
        Stages of the latest launch or teardown. Launch stages are create_plane,
        prepare_hosts, join_workers, apply_plane, and issue_access. Teardown
        stages include workers and the control-plane stage (namespace for
        Kubernetes, stack for Slurm), plus nodes or storage when those steps
        fail.
      properties:
        stages:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
                description: Stable stage identifier.
              label:
                type: string
                description: Display label for the stage.
              status:
                type: string
                enum:
                  - pending
                  - running
                  - completed
                  - failed
              detail:
                type:
                  - string
                  - 'null'
                description: Failure reason or worker confirmation count, when available.
  responses:
    Unauthorized:
      description: >-
        The credential is missing, invalid, revoked, or no longer belongs to a
        current organization member. Check the HTTP status before parsing the
        body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >-
        The credential lacks access to this operation, or the organization
        requires approval. An API key does not bypass these checks.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error:
      description: >-
        Unsuccessful request. Check HTTP status first. Errors may have
        detail.code/detail.message, a string detail and optional top-level code,
        or an empty/non-JSON body. 401: invalid credential; 403: access or
        approval required; 404: not visible or credentials not ready; 409:
        lifecycle conflict; 429: back off; 5xx: service failure. Inspect current
        state before retrying mutations.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    OrnnApiKey:
      type: http
      scheme: bearer
      bearerFormat: ornn_sk_...
      description: >-
        Create an organization API key in Account Settings > Developer. Do not
        send this key to the Kubernetes API server.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.