Skip to content
OpenRelay is in early access, and the /v1 API is stable. New capabilities ship in the changelog.
API ReferenceComputePods

Create a pod

Runs your container image as a pod on gpuCount whole GPUs of one node, with SSH access, at the on-demand rate fixed at creation, and returns it as a VmSummary. Compute-fabric pod (BYO container image + SSH keys): a hardened GPU container on gpuCount whole native-driver GPUs of one node. Admission claims free device-request GPU units (see listPodCapacity for what is claimable), snapshots the on-demand rate immutably onto the pod, and drives the guest workflow. A valid request the fleet has no room for right now answers 503 with a capacity code; a GPU count no node could ever hold for the org answers 400 GPU_COUNT_NOT_ALLOCATABLE; and an org without the pod tier answers 409 FEATURE_DISABLED.

Required permission

Requires the compute.create permission. See Permissions for the roles and API key permissions that include it.

Command line

The orl CLI wraps this endpoint:

orl pods create --image <image> --ssh-key-ids <ssh-key-ids>
POST
/v1/pods

Authorization

apiKey
headerAuthorizationBearer <token>

OpenRelay API key. Send it as Authorization: Bearer or_… (legacy vl_… keys still work).

Header Parameters

Idempotency-Key?string

Makes a retried create safe. Choose one value per create you mean to make, 1 to 512 bytes (bytes, not characters), such as a UUID, and send it again on every retry of that create. The first request with a key runs, and a 2xx answer is kept for 24 hours: a repeat with the same key and the same body gets that answer back, with the same status and the header Idempotent-Replayed: true, and creates nothing. A batch create compares the body byte for byte; a VM or pod create compares the fields it decodes, so whitespace and key order do not count. A repeat while the first request is still running answers 409; repeat it a second later. The same key with a different body answers 422. An answer other than a 2xx is not kept, so a retry after a 4xx or a 5xx runs again. A 2xx too large to keep holds the key without it: every repeat answers 409 and creates nothing. Keys are scoped to the organization and the operation.

Length1 <= length

Request Body

application/json
  1. body

Request to create a compute-fabric pod: a RunPod-style bring-your-own container image + SSH keys guest. A focused subset of CreateVmRequest (no qcow2 template / kernel modules / privileged mode).

name?string
gpuModelId?string
computeClass?string

purchase option. on_demand (pay per second, no commitment) is the only class sold; reserved is a deprecated alias that is stored as on_demand. interruptible is retired and rejected with 400 COMPUTE_CLASS_RETIRED; it remains listed only until the deprecation window closes.

Default"on_demand"
Value in"on_demand""reserved""interruptible"
image*string

tenant container image ref (required)

gpuCount?integer

how many whole GPUs this pod gets. All of them are claimed on ONE node and passed to the container together; the pod is priced for gpuCount GPUs. Omitted = 1. A count no single node could ever hold for your org is refused with 400 GPU_COUNT_NOT_ALLOCATABLE; one that some node could hold but none has free right now is refused with 503 INSUFFICIENT_GPU_CAPACITY (maxGpuCount on /v1/pods/capacity is the largest a create can take now).

Range1 <= value <= 8
Default1
sshKeyIds*array<string>

Org SSH key ids injected into the guest. At least one is required and every id must name a live key of this org: the data-plane gateway authorizes guest SSH against exactly this list, so a pod created without one has no SSH access. Attaching or detaching a key later takes effect within about a minute, with no restart.

Items1 <= items <= 64
envVars?
httpPort?integer

in-guest HTTP port exposed on the endpoint

Default80
shmSizeGb?integer

size of the pod's private /dev/shm in GiB (docker --shm-size). Optional; the maximum is half the pod's memory limit on its placement node (itself the pod's GPU-proportional share of node RAM), and a larger value is refused with 400 POD_ADMISSION_FAILED. Omitted lets the platform pick a safe default: that same maximum for a pod that owns its whole node, 2 GiB per GPU (capped at the maximum) for a shared multi-GPU pod, and docker's default for a shared single-GPU pod. Raise this when a multi-GPU NCCL / PyTorch DataLoader workload needs more shared memory than the default.

Range1 <= value <= 8192
public?boolean

true = open endpoint (no data-plane auth); default false requires an org API key

Defaultfalse
volumeGb?integer

size in GB of the pod's persistent volume, mounted read-write at /workspace. Omitted = 50. The volume lives on the pod's node and is kept across stop, start, restart, container crashes, node reboots and interruptions; it is deleted only when the pod is deleted (or after 7 days interrupted with its node gone). Everything outside /workspace is the container's own filesystem and is reset whenever the container is recreated. Fixed at create; there is no resize.

Range10 <= value <= 1024

Response Body

Created

application/json
  1. response
id*string
organizationId*string
name*string
status*string

deploying, running, stopped, failed, terminated, or interrupted; a row can also carry the queued status pending. interrupted means it served and is not serving now: it keeps its node, GPU and disk, and is not billed. A VM is interrupted while its node is offline and resumes when the node returns; a pod is interrupted for that and for losing its supervisor or its job on a live node, which the platform recovers by re-submitting it. After 7 days interrupted a VM is stopped (disk kept) and a pod is deleted.

statusReason?string

Cause of the current status. The machine-readable values are "node_lost" (the host went offline and is expected back, so the disk is preserved), "node_removed" (the host was decommissioned, so the disk is gone and a restart deploys fresh elsewhere), "vm_exited", "user_stopped", "user_terminated", "user_restarted", "spot_reclaimed_by_capacity_owner", "spot_preempted_for_reservation_tenant", "auto_stopped_insufficient_balance", "auto_stopped_account_suspended", "auto_stopped_organization_deleted", the prefix "container failed to start: " followed by the container runtime's own message, and on a running workload the prefix "node leaving at " followed by the RFC 3339 time its host is removed, when the workload ends with node_removed. Anything else is free text for a human to read.

gpuModelId?string
gpuCount?integer
endpointUrl?string
volumeGb?integer

pods only: size in GB of the pod's persistent /workspace volume.

public?boolean

true = open endpoint (no data-plane auth); false = require an org API key

createdAt?string
provisioningStage?string
resourceSize?string
tier?string
diskSizeGb?integer
gpuModelName?string
gpuManufacturer?string

GPU vendor from the catalog, the same value as GpuModel.manufacturer (NVIDIA, AMD); absent on a CPU-only row

pricePerHourCents?integer
serviceType?string

managed-service tag; empty for a plain VM

managedBy?string

platform owner of this row ("serving" = inference serving replica, read-only on customer surfaces); empty for a customer-launched VM

capabilityTier?string

compute-fabric capability tier (e.g. "pod"); empty for a plain VM

computeClass?string

compute-fabric purchase option (on_demand; pods created before the rename carry the legacy reserved or interruptible values); empty for a plain VM

imageUrl?string

tenant container image (pods)

Example Request
curl -X POST 'https://api.openrelay.inc/v1/pods' \  -H 'Content-Type: application/json' \  -d '{  "name": "cuda-devbox",  "gpuModelId": "rtx-4090",  "computeClass": "on_demand",  "image": "ghcr.io/acme/cuda-devbox:latest",  "sshKeyIds": [    "3f1c7f2e-6a41-4a3f-9d0b-2c8e5a7b1d44"  ],  "httpPort": 8000,  "envVars": {    "HF_TOKEN": "hf_xxxxxxxx"  }}'
Example Response
{  "id": "string",  "organizationId": "string",  "name": "string",  "status": "string",  "statusReason": "string",  "gpuModelId": "string",  "gpuCount": 0,  "endpointUrl": "string",  "volumeGb": 0,  "public": true,  "createdAt": "string",  "provisioningStage": "string",  "resourceSize": "string",  "tier": "string",  "diskSizeGb": 0,  "gpuModelName": "string",  "gpuManufacturer": "string",  "pricePerHourCents": 0,  "serviceType": "string",  "managedBy": "string",  "capabilityTier": "string",  "computeClass": "string",  "imageUrl": "string"}