Cloud API Reference
Base URL: https://api.smolmachines.com
All endpoints require Authorization: Bearer <api_key> header.
Machines
Create a machine
POST /v1/machines {
"name": "my-machine",
"source": { "type": "image", "reference": "alpine" },
"resources": { "cpus": 1, "memoryMb": 256, "diskGb": 20 },
"network": { "mode": "open" },
"env": { "APP_ENV": "production" },
"workdir": "/workspace",
"autoStopSeconds": 300,
"ttlSeconds": 3600,
"ephemeral": false,
"mounts": [{ "volume": "data-vol", "mountPath": "/data" }]
} All fields except source are optional. Returns the machine object with state: "stopped".
List machines
GET /v1/machines Returns an array of all your machines.
Get a machine
GET /v1/machines/:id Start a machine
POST /v1/machines/:id/start Stop a machine
POST /v1/machines/:id/stop Compute billing stops immediately. Storage persists.
Delete a machine
DELETE /v1/machines/:id Exec
Execute a command
POST /v1/machines/:id/exec {
"command": "echo hello",
"env": { "MY_VAR": "value" },
"cwd": "/workspace",
"timeoutSeconds": 30,
"stdin": "input data\n",
"stream": false
} command can be a string (runs via sh -lc) or an array (argv form: ["python3", "app.py"]).
If the machine is stopped, it auto-starts before executing.
TIP
`exec` calls — running commands inside a machine — are never charged and never rate-limited. Run as many as you want.Response:
{
"stdout": "hello\n",
"stderr": "",
"exitCode": 0,
"durationMs": 14,
"machineId": "mach-abc123"
} Streaming exec (SSE)
Set "stream": true to receive Server-Sent Events as the command runs.
Execute code
POST /v1/machines/:id/code {
"language": "python",
"code": "print(sum(range(100)))"
} Supported languages: python, javascript/node.
Files
Upload a file
PUT /v1/machines/:id/files/{path} Body: raw file bytes.
Download a file
GET /v1/machines/:id/files/{path} Sessions
Sessions maintain environment variables and working directory across multiple exec calls.
Create a session
POST /v1/machines/:id/sessions {
"cwd": "/workspace",
"env": { "PROJECT": "myapp" }
} Execute in a session
POST /v1/machines/:id/sessions/:sessionId/exec Same body as regular exec. Session env and cwd are inherited (request overrides).
List sessions
GET /v1/machines/:id/sessions Delete a session
DELETE /v1/machines/:id/sessions/:sessionId Events
Get machine events
GET /v1/machines/:id/events Returns lifecycle events (start failures, rescheduling, etc.) for debugging.
Volumes
Create a volume
POST /v1/volumes {
"name": "my-data",
"sizeGb": 10
} List volumes
GET /v1/volumes Delete a volume
DELETE /v1/volumes/:id Mount volumes when creating a machine using the mounts field.
Usage
Query usage
GET /v1/usage?tenantId=TENANT&from=ISO_DATE&to=ISO_DATE Response:
{
"tenantId": "acme-corp",
"totalUptimeSeconds": 86400,
"cpuHours": 48.0,
"memoryGbHours": 12.0,
"machineCount": 5,
"execCount": 230,
"execDurationMs": 45000
} API Keys
Create an API key
POST /v1/apikeys {
"description": "CI deploy key",
"scopes": ["machine:create", "machine:exec"],
"expiresInDays": 30
} List API keys
GET /v1/apikeys Revoke an API key
DELETE /v1/apikeys/:id Health
GET /health Public endpoint, no auth required.
Error responses
All errors return a plain text body with an appropriate HTTP status code:
| Status | Meaning |
|---|---|
| 400 | Bad request (validation failed) |
| 401 | Unauthorized (missing or invalid key) |
| 403 | Forbidden (insufficient scopes) |
| 404 | Not found (or belongs to another tenant) |
| 409 | Conflict (duplicate name) |
| 422 | Unprocessable (quota exceeded, no capacity) |
| 429 | Rate limited |
| 500 | Internal server error |