---
title: "Create a VM"
method: POST
path: "/v1/orgs/{orgId}/vms/create"
tags: ["VMs"]
---

# Create a VM

`POST /v1/orgs/{orgId}/vms/create`

## Path parameters

- `orgId` string, required

## Request body

- CreateVmRequest
  - `allowFallback` boolean
  - `cloudInit` string — Startup script run inside the guest the first time this VM boots. Must begin with a shebang (e.g. "#!/bin/bash"); a raw cloud-config document is rejected. Runs once per disk, not once per boot: a stop/start keeps the disk and does not re-run it, while a VM that lands on a fresh disk does. It runs as root once the network and your SSH keys are up, and its output goes to the VM's logs. A script that fails does not stop the VM from starting or from being billed, so check the logs rather than assuming it succeeded.
  - `containerCommand` string[]
  - `containerPort` integer
  - `diskSizeGb` integer
  - `envVars` object
  - `gpuCount` integer
  - `gpuModelId` string
  - `healthCheckPath` string
  - `healthCheckPort` integer
  - `healthChecks` string[]
  - `imageUrl` string
  - `kernelModules` string[]
  - `name` string, required
  - `nodeId` string — Place this VM on a specific node. Required to use capacity reserved to your org; omit to use the public pool. There is no fallback: if the node has no room for this GPU count the request is refused rather than placed elsewhere. A node you have no rights on reads as not found.
  - `preferredRegions` string[]
  - `privileged` boolean
  - `public` boolean — true = open endpoint (no data-plane auth); default false requires an org API key
  - `registryCredentialId` string
  - `resourceSize` string
  - `sshKeyIds` string[]
  - `templateId` string
  - `tier` string

## Response `200`

Created

- VmSummary
  - `capabilityTier` string — compute-fabric capability tier (e.g. "pod"); empty for a plain VM
  - `computeClass` string — compute-fabric compute class (interruptible|reserved); empty for a plain VM
  - `createdAt` string
  - `diskSizeGb` integer
  - `endpointUrl` string
  - `gpuCount` integer
  - `gpuModelId` string
  - `gpuModelName` string
  - `id` string, required
  - `imageUrl` string — tenant container image (pods)
  - `managedBy` string — platform owner of this row ("serving" = inference serving replica, read-only on customer surfaces); empty for a customer-launched VM
  - `name` string, required
  - `organizationId` string, required
  - `pricePerHourCents` integer
  - `provisioningStage` string
  - `public` boolean — true = open endpoint (no data-plane auth); false = require an org API key
  - `resourceSize` string
  - `serviceType` string — managed-service tag; empty for a plain VM
  - `status` string, required
  - `statusReason` string — human-readable cause for failed/stuck states
  - `tier` string

## Other responses

- `400` — The request is invalid
- `401` — Missing or invalid API key
- `403` — API key lacks the required scope
- `409` — The request conflicts with existing state
- `503` — The request is valid but the capacity it needs is momentarily unavailable: a transient saturation that clears on node or VM turnover, not a durable conflict. Codes: NODE_AT_CAPACITY, INSUFFICIENT_GPU_CAPACITY, INSUFFICIENT_CPU_CAPACITY, INSUFFICIENT_IP_CAPACITY. Retry the same request with exponential backoff; the Retry-After header suggests how long to wait.

---

[API](https://skmtc.net/openrelay/apis/openrelay-api.md) · [All operations](https://skmtc.net/openrelay/apis/openrelay-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/openrelay/openrelay-api/revisions/7e2fe85577f4/schema)
