Simplifyd CloudSimplifyd Cloud

Virtual machines

Create, boot, stop, start and delete virtual machines, including desktop machines for AI agents, from your own code.

A virtual machine is a service like any other: it lives in an environment, on the project's private network, and is created, read and deleted through the same service endpoints. Stopping and starting are the two calls only VMs have.

A desktop machine is a VM created from the ubuntu-24.04-desktop image. Once it is running, an AI agent drives it through the computer API.

Every call takes a project token (sk_proj_…) as a bearer token. Throughout this page:

BASE = https://api.cloud.simplifyd.com/v1/workspaces/{workspace}/projects/{project}/envs/{env}/svcs
{workspace}, {project}, {env}Ids. See how resources are addressed.
{service}The VM's id, the slug returned when you create it.

For desktop session tokens, see Show the screen in your own app. For screenshots, display details and computer actions, see Computer API.

Endpoints

MethodPathWhat it does
POST{BASE}Creates a VM
POST{BASE}/{service}/deploymentsBoots a new VM
GET{BASE}/{service}Its configuration and status
POST{BASE}/{service}/vm/stopShuts it down, keeping its disk
POST{BASE}/{service}/vm/startBoots a stopped VM
DELETE{BASE}/{service}Deletes it and its disk

A VM's life is: create it, deploy it once to boot it, then stop and start it as you need it. Delete it when you are done.


Create a VM

POST {BASE}
Content-Type: application/json

Creates the VM. It does not boot until you deploy it.

A VM starts with 2 vCPUs and 4 GB of memory. In a workspace that has never been funded it gets 1 vCPU instead.

Body

FieldDescription
typeRequired"vm".
nameOptionalDisplay name. Defaults to VM.
kubevirt_vm_svc.imageRequiredubuntu-22.04, or ubuntu-24.04-desktop for a desktop machine.
kubevirt_vm_svc.storage_gbRequiredBoot disk size in GB: 10 to 200, or 20 to 200 for a desktop machine. It cannot be made smaller later.
kubevirt_vm_svc.ssh_authorized_keysRequired for ubuntu-22.041 to 10 public keys, installed for the ubuntu user. Optional for a desktop machine, which an agent reaches through its screen and the computer API.
curl -X POST "$BASE" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "vm",
    "name": "research",
    "kubevirt_vm_svc": { "image": "ubuntu-24.04-desktop", "storage_gb": 20 }
  }'
const response = await fetch(BASE, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'vm',
    name: 'research',
    kubevirt_vm_svc: { image: 'ubuntu-24.04-desktop', storage_gb: 20 },
  }),
});
const vm = await response.json();
client := cloud.NewClient(cloud.WithToken(os.Getenv("SIMPLIFYD_API_TOKEN")))
svcs := client.Workspace(ws).Project(p).Env(env).Services()

vm, err := svcs.Create(ctx, cloud.CreateServiceInput{
	Name: "research",
	Type: cloud.ServiceTypeVM,
	VM: &cloud.VMInput{
		Image:     cloud.VMImageDesktop,
		StorageGB: 20,
	},
})

Response

201 Created. The new service, trimmed here to the fields that matter:

{
  "slug": "01a137c0-b1af-7298-a143-1aa7f2557b0b",
  "name": "research",
  "type": "vm",
  "vcpus": 2,
  "memory": 4096,
  "replicas": 1,
  "region": "ng-west-1"
}

slug is the {service} in every other call. memory is in MB.

Errors

StatusWhen
400The image is not one of the above, storage_gb is missing or out of range, or a server image has no SSH key. message names the field.
402The workspace is suspended for an unpaid balance.

Boot it for the first time

POST {BASE}/{service}/deployments?auto_approve_change_sets=true

Boots a VM you have just created. Call it once. After that, use stop and start.

Query parameters

ParameterDescription
auto_approve_change_setsOptionaltrue applies any pending changes to the service as part of this deploy. Without it, a service with pending changes is refused with 400.
curl -X POST "$BASE/$SERVICE/deployments?auto_approve_change_sets=true" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"
await fetch(`${BASE}/${service}/deployments?auto_approve_change_sets=true`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
_, err = svcs.Deploy(ctx, vm.Slug, cloud.DeployOptions{AutoApproveChangeSets: true})

Response

201 Created

{ "success": true }

The VM is booting. Get it to watch status reach running. A desktop machine's screen and computer API are usually ready one to two minutes after the call; until then the computer API answers 503.


Get a VM

GET {BASE}/{service}
curl "$BASE/$SERVICE" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"
const response = await fetch(`${BASE}/${service}`, {
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
const vm = await response.json();
vm, err := svcs.Get(ctx, slug)
if vm.VM.HasDesktop() && vm.Status == cloud.ServiceStatusRunning {
	// ready to drive, give or take the desktop signing in
}

Response

200 OK. Trimmed to the fields that matter for a VM:

{
  "slug": "01a137c0-b1af-7298-a143-1aa7f2557b0b",
  "name": "research",
  "type": "vm",
  "status": "running",
  "vcpus": 2,
  "memory": 4096,
  "region": "ng-west-1",
  "private_hostname": "research.p28xl.0000001.simplifyd.internal",
  "kubevirt_vm_svc": {
    "image": "ubuntu-24.04-desktop",
    "storage_gb": 20
  }
}
FieldDescription
statuspending before the first deploy; deploying or starting while it boots; running; stopped; failed if it could not start, with status_message saying why.
private_hostnameWhere other services in the project reach it.
kubevirt_vm_svcThe image, disk size and SSH keys it was created with.

Stop a VM

POST {BASE}/{service}/vm/stop

Shuts the VM down. Its disk is kept, with everything on it. Compute stops being billed; the disk is billed while the VM is stopped.

curl -X POST "$BASE/$SERVICE/vm/stop" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"
await fetch(`${BASE}/${service}/vm/stop`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
err = svcs.StopVM(ctx, slug)

Response

200 OK

{ "success": true }

status is stopped from then on.

Errors

StatusWhen
400The service is not a VM: "service does not support stop/start".

Start a VM

POST {BASE}/{service}/vm/start

Boots a stopped VM from the disk it was stopped with.

curl -X POST "$BASE/$SERVICE/vm/start" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"
await fetch(`${BASE}/${service}/vm/start`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
err = svcs.StartVM(ctx, slug)

Response

200 OK

{ "success": true }

status is deploying until the VM is up, then running. As after the first boot, a desktop machine takes one to two minutes to be ready.

Errors

StatusWhen
400The service is not a VM, or it has more than 1 vCPU in a workspace that has never been funded.

Delete a VM

DELETE {BASE}/{service}

Deletes the VM and its disk. This cannot be undone.

curl -X DELETE "$BASE/$SERVICE" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"
await fetch(`${BASE}/${service}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
err = svcs.Delete(ctx, slug)

Response

200 OK, with the deleted service in the same shape as get.


Errors

Errors carry a message written to be shown to a person:

{
  "type": "VALIDATION_ERROR",
  "message": "kubevirt_vm_svc.storage_gb must be between 20 and 200"
}
StatusMeaning
400The request cannot be done as asked; message says why.
401The token is missing, malformed or deleted.
403The token does not cover this workspace, project or environment.
5xxOur side.