Sandboxes are ephemeral Firecracker microVMs that restore from a pre-seeded snapshot, accept exec and file operations, expose previews, and are billed by compute/runtime usage. They are designed for AI-agent code execution workloads, artifact generation, and app previews.
Base path: /api/v1/sandboxes
For higher-level access, use the official SDKs: Python, TypeScript, Go, Java, Elixir.
List Sandbox Templates
GET /api/v1/sandbox-templates
Returns the platform-managed sandbox template catalog. Pass one of these IDs as template_id when creating a sandbox. The catalog describes what your app should run: workdir, install command, start command, preview port, readiness probe, and artifact paths.
curl https://api.miosa.ai/api/v1/sandbox-templates
-H "Authorization: Bearer $MIOSA_API_KEY" Response — 200 OK
{
"default_template_id": "miosa-sandbox",
"data": [
{
"id": "nextjs",
"name": "Next.js",
"image_id": "miosa-sandbox",
"category": "web",
"cpu_count": 2,
"memory_mb": 2048,
"disk_mb": 4096,
"workdir": "/workspace",
"preview_port": 3000,
"install_command": "npm install",
"start_command": "npm run dev -- --hostname 0.0.0.0 --port 3000",
"readiness_probe": {
"type": "http",
"url": "http://127.0.0.1:3000"
}
}
]
} Use GET /api/v1/sandbox-templates/{id} to fetch one template. Add ?include_aliases=true on the list endpoint to include compatibility aliases such as python-3.12, react-vite, and static.
Sandbox Template BuildSpec
Phase 4 introduces the public BuildSpec contract for reusable sandbox templates. The API validates and normalizes BuildSpecs, persists tenant-owned template records, queues template build records, and runs a builder worker that turns the normalized BuildSpec into a Firecracker rootfs artifact.
Get the BuildSpec schema
GET /api/v1/sandbox-templates/build-spec
curl https://api.miosa.ai/api/v1/sandbox-templates/build-spec
-H "Authorization: Bearer $MIOSA_API_KEY" Validate a BuildSpec
POST /api/v1/sandbox-templates/validate
curl -X POST https://api.miosa.ai/api/v1/sandbox-templates/validate
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{
"build_spec": {
"from": "node:22-bookworm",
"vcpu": 2,
"memoryMib": 2048,
"diskMib": 8192,
"steps": [
{"run": "corepack enable"},
{"workdir": "/workspace"}
],
"env": {"NODE_ENV": "development"},
"workdir": "/workspace",
"user": "root",
"startCmd": "pnpm dev --host 0.0.0.0 --port 3000",
"readyCmd": "curl -f http://127.0.0.1:3000",
"previewPort": 3000,
"artifactPaths": ["/workspace"]
}
}' Response:
{
"valid": true,
"build_spec": {
"from": "node:22-bookworm",
"vcpu": 2,
"memoryMib": 2048,
"diskMib": 8192,
"steps": [{"run": "corepack enable"}, {"workdir": "/workspace"}],
"env": {"NODE_ENV": "development"},
"workdir": "/workspace",
"user": "root",
"startCmd": "pnpm dev --host 0.0.0.0 --port 3000",
"readyCmd": "curl -f http://127.0.0.1:3000",
"previewPort": 3000,
"artifactPaths": ["/workspace"]
}
} Validation errors use stable codes:
| Code | Meaning |
|---|---|
REQUIRED | A required field such as from is missing. |
UNSUPPORTED_BASE_IMAGE | Alpine/distroless bases are rejected for public agent templates. |
OUT_OF_RANGE | Resource values are outside tenant-safe defaults. |
INVALID_INTEGER | Numeric fields are not integers. |
INVALID_PORT | Preview port is outside 1..65535. |
INVALID_PATH | Workdir or artifact path is not absolute. |
INVALID_STEP | A build step is not a supported object. |
Create a custom template
POST /api/v1/sandbox-templates
curl -X POST https://api.miosa.ai/api/v1/sandbox-templates
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{
"name": "Agent Web App",
"slug": "agent-web-app",
"description": "Reusable Node app sandbox",
"build_spec": {
"from": "node:22-bookworm",
"vcpu": 2,
"memoryMib": 2048,
"diskMib": 8192,
"startCmd": "pnpm dev --host 0.0.0.0 --port 3000",
"readyCmd": "curl -f http://127.0.0.1:3000",
"previewPort": 3000,
"artifactPaths": ["/workspace"]
}
}' Queue a template build
POST /api/v1/sandbox-templates/{template_id}/builds
curl -X POST https://api.miosa.ai/api/v1/sandbox-templates/tpl_123/builds
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{}' Build records start in queued. The builder worker moves them through building, snapshotting, certifying, distributing, and then ready or failed. ready means the rootfs exists, a Firecracker memory snapshot has been seeded,
certification passed, and the rootfs/snapshot artifacts have been published to
the fleet artifact source. Each compute host reconciles or fetches the artifacts
before it boots that custom template. After that, pass the template slug to POST /api/v1/sandboxes as template_id.
If a custom template exists but is not ready, sandbox creation returns 409 TEMPLATE_NOT_READY. If snapshot seeding fails, the build fails with SNAPSHOT_FAILED; if certification fails, it fails with CERTIFICATION_FAILED.
Read template builds
curl https://api.miosa.ai/api/v1/sandbox-templates/tpl_123/builds
-H "Authorization: Bearer $MIOSA_API_KEY"
curl https://api.miosa.ai/api/v1/sandbox-template-builds/build_123
-H "Authorization: Bearer $MIOSA_API_KEY" Observe and control template builds
curl https://api.miosa.ai/api/v1/sandbox-template-builds/build_123/logs
-H "Authorization: Bearer $MIOSA_API_KEY"
# Browsers/EventSource cannot send Authorization headers. Issue a short-lived
# SSE ticket first, then pass it as ?ticket=...
curl -X POST https://api.miosa.ai/api/v1/auth/sse-ticket
-H "Authorization: Bearer $MIOSA_API_KEY"
curl -N "https://api.miosa.ai/api/v1/sandbox-template-builds/build_123/logs/stream?ticket=$SSE_TICKET"
-H "Accept: text/event-stream"
curl -X POST https://api.miosa.ai/api/v1/sandbox-template-builds/build_123/cancel
-H "Authorization: Bearer $MIOSA_API_KEY"
curl -X POST https://api.miosa.ai/api/v1/sandbox-template-builds/build_123/retry
-H "Authorization: Bearer $MIOSA_API_KEY" /logs returns persisted lifecycle events from build metadata. /logs/stream opens an SSE stream that first replays persisted events, then emits live build_event messages until the build reaches ready, failed, or cancelled.
Example SSE payload:
event: build_event
data: {"event":"snapshotting","state":"snapshotting","at":"2026-05-13T10:00:00Z"} Retry is allowed for failed or cancelled builds. Cancel is accepted for
non-terminal builds and records BUILD_CANCELLED.
BuildSpec fields
| Field | Type | Description |
|---|---|---|
from | string | OCI base image. Debian/Ubuntu/Bookworm bases are recommended. |
vcpu | integer | Template-owned vCPU count. |
memoryMib | integer | Template-owned memory in MiB. |
diskMib | integer | Template-owned root disk in MiB. |
steps | array | Ordered build steps. Each step may define run, workdir, or env. |
env | object | Runtime-default environment variables. |
workdir | string | Runtime working directory. Defaults to /workspace. |
user | string | Runtime user. Defaults to root. |
startCmd | string | Long-running command used by /template/start. |
readyCmd | string | Readiness command for the started app. |
previewPort | integer | Default preview port for /expose and template start. |
artifactPaths | array | Paths returned by the artifact manifest. |
Create a Sandbox
POST /api/v1/sandboxes
Spawns a new sandbox VM. The API returns the sandbox record immediately after the create request is accepted; poll GET /api/v1/sandboxes/{id} or subscribe to events until state is running and ready is true.
The current production alias, miosa-sandbox, points at miosa-sandbox. On the deployed six-host fleet, the snapshot path benchmarks at 48 ms p50 / 51 ms p95 runtime boot and 156 ms p50 / 208 ms p95 create-to-ready.
Auth
Bearer token required.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | No | Boot template. Defaults to miosa-sandbox. See available templates below. |
cpu_count | integer | No | vCPU count. Default 1, default cap 4. |
memory_mb | integer | No | RAM in MB. Default 1024, default cap 8192. |
disk_mb | integer | No | Disk in MB. Default 3072, default cap 10240. |
timeout_sec | integer | No | Max wall-clock seconds before force-destroy. Day-long/always-on use is available when billing and policy allow it. |
env | object | No | Key-value env vars injected at boot. |
metadata | object | No | Arbitrary caller-supplied metadata stored on the record. |
auto_start | boolean | No | If true, MIOSA starts the selected template after the sandbox reaches running. Generated-app platforms usually keep this false, write files first, then call /template/start. |
workspace_id | UUID | No | Existing MIOSA workspace that owns the sandbox. Defaults to the organization default workspace. |
workspace_slug | string | No | Existing or auto-created workspace slug. |
workspace_name | string | No | Workspace display name if auto-created. |
project_id | UUID | No | Existing MIOSA project that owns the sandbox. Defaults to the workspace default project. |
project_slug | string | No | Existing or auto-created project slug inside the workspace. |
project_name | string | No | Project display name if auto-created. |
external_workspace_id | string | No | Your customer/account/workspace ID. |
external_user_id | string | No | Your end-user ID. |
external_project_id | string | No | Your project/app/document ID. |
Available templates:
template_id | Description |
|---|---|
miosa-sandbox | Stable production alias for the current sandbox image. |
nextjs | Next.js app preview profile. |
vite-react | Vite React app preview profile. |
python | Python script/artifact generation profile. |
streamlit | Streamlit data app preview profile. |
gradio | Gradio ML/demo app preview profile. |
static-html | Static HTML/CSS/JS preview profile. |
Request Headers
| Header | Description |
|---|---|
Idempotency-Key | Client-generated key (UUID recommended). Same key within 24 h returns the existing sandbox instead of creating a new one. |
Response — 201 Created
{
"id": "sbx_01j9xr2t4fk8me3n5q",
"tenant_id": "tnt_abc123",
"owner_id": "usr_def456",
"workspace_id": "550e8400-e29b-41d4-a716-446655440000",
"project_id": "660e8400-e29b-41d4-a716-446655440001",
"external_workspace_id": "clinic_123",
"external_user_id": "dr-smith-456",
"external_project_id": "project_789",
"template_id": "miosa-sandbox",
"image_id": "miosa-sandbox",
"state": "provisioning",
"ready": false,
"cpu_count": 1,
"memory_mb": 1024,
"disk_size_mb": 3072,
"boot_path": null,
"boot_ms": null,
"preview_url": "https://sbx01j9x.sandbox.miosa.app",
"timeout_sec": 300,
"total_runtime_sec": null,
"metadata": {},
"created_at": "2026-04-25T10:00:00Z",
"started_at": null,
"ready_at": null,
"destroyed_at": null
} Errors
| Status | Code | Cause |
|---|---|---|
| 400 | INVALID_TEMPLATE | template_id is not a recognized template. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits to provision the VM. |
| 409 | SANDBOX_LIMIT_EXCEEDED | Tenant has reached the concurrent sandbox limit (default 10). |
| 422 | VALIDATION_ERROR | Invalid field values (for example, a resource request above the tenant’s plan cap). |
Start a Template App
POST /api/v1/sandboxes/{id}/template/start
After your platform writes generated files into /workspace, call this endpoint to run the selected template lifecycle. MIOSA runs the template install command, launches the start command in the background, stores PID/log paths, and returns the preview URL.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/template/start
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"install":true}' Response:
{
"data": {
"status": "started",
"template_id": "nextjs",
"workdir": "/workspace",
"preview_port": 3000,
"preview_url": "https://abc12345.sandbox.miosa.app",
"logs_path": "/tmp/miosa-run/template.log",
"pid_path": "/tmp/miosa-run/template.pid",
"artifact_paths": ["/workspace"]
}
} You can override install_command, start_command, port, or workdir in the request body when your generated project needs a custom command.
Get Artifacts
GET /api/v1/sandboxes/{id}/artifacts
Returns the template artifact contract and current lifecycle metadata.
curl https://api.miosa.ai/api/v1/sandboxes/{id}/artifacts
-H "Authorization: Bearer $MIOSA_API_KEY" The response includes preview.url, preview.port, artifact paths, and template lifecycle log/PID paths.
curl -X POST https://api.miosa.ai/api/v1/sandboxes
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{
"template_id": "miosa-sandbox",
"workspace_slug": "dr-smith-clinic",
"workspace_name": "Dr. Smith Clinic",
"project_slug": "lead-magnet",
"project_name": "Lead Magnet",
"external_workspace_id": "clinic_123",
"external_user_id": "dr-smith-456",
"external_project_id": "project_789",
"memory_mb": 1024,
"env": {"MY_VAR": "hello"}
}' List Sandboxes
GET /api/v1/sandboxes
Returns all sandboxes belonging to the authenticated tenant.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
workspace_id | UUID | Filter to one MIOSA workspace |
project_id | UUID | Filter to one MIOSA project |
external_workspace_id | string | Filter by your customer/account ID |
external_user_id | string | Filter by your end-user ID |
external_project_id | string | Filter by your project/app/document ID |
state | string | Filter by lifecycle state: provisioning, running, paused, destroyed, error. |
Auth
Bearer token required.
Response — 200 OK
{
"data": [
{
"id": "sbx_01j9xr2t4fk8me3n5q",
"template_id": "miosa-sandbox",
"state": "running",
"cpu_count": 1,
"memory_mb": 1024,
"created_at": "2026-04-25T10:00:00Z"
}
]
} curl "https://api.miosa.ai/api/v1/sandboxes?state=running"
-H "Authorization: Bearer $MIOSA_API_KEY" Get a Sandbox
GET /api/v1/sandboxes/{id}
Auth
Bearer token required.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Sandbox ID. |
Response — 200 OK
Full sandbox object (same shape as the create response with current state).
Errors
| Status | Code | Cause |
|---|---|---|
| 404 | NOT_FOUND | Sandbox does not exist or belongs to a different tenant. |
curl https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q
-H "Authorization: Bearer $MIOSA_API_KEY" Destroy a Sandbox
DELETE /api/v1/sandboxes/{id}
Terminates the VM immediately and settles billing.
Auth
Bearer token required.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Sandbox ID. |
Response — 200 OK
{
"id": "sbx_01j9xr2t4fk8me3n5q",
"state": "destroyed",
"total_runtime_sec": 42
} Errors
| Status | Code | Cause |
|---|---|---|
| 404 | NOT_FOUND | Sandbox does not exist or belongs to a different tenant. |
curl -X DELETE https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q
-H "Authorization: Bearer $MIOSA_API_KEY" Execute a Command
POST /api/v1/sandboxes/{id}/exec
Runs a shell command inside the sandbox. Blocks until the process exits.
Auth
Bearer token required.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Sandbox ID. Must be in running state. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
command | string | Yes | Shell command to execute. |
timeout | integer | No | Per-command timeout in seconds. Default 30, max 300. |
working_dir | string | No | Working directory inside the VM. Default /root. |
env | object | No | Env vars for this invocation only. |
Response — 200 OK
{
"data": {
"sandbox_id": "sbx_01j9xr2t4fk8me3n5q",
"stdout": "2\n",
"stderr": "",
"exit_code": 0
}
} Errors
| Status | Code | Cause |
|---|---|---|
| 409 | SANDBOX_NOT_RUNNING | Sandbox is not in running state. |
| 504 | — | Command timed out. |
curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/exec
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"command": "python3 -c "print(1+1)"", "timeout": 30}' Stream Command Output
POST /api/v1/sandboxes/{id}/exec/stream
Runs a command and streams stdout/stderr events as Server-Sent Events. Use this for installer output, long-running agent tasks, and build logs that should show progress before the command exits.
Request body is the same as /exec.
curl -N -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/exec/stream
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Accept: text/event-stream"
-H "Content-Type: application/json"
-d '{"command":"npm install && npm run build","working_dir":"/workspace","timeout":300}' Example events:
event: stdout
data: {"line":"added 342 packages"}
event: exit
data: {"exit_code":0} Open a Terminal Session
POST /api/v1/sandboxes/{id}/terminal
Creates a PTY session inside a running sandbox and returns a short-lived stream token for browser WebSocket clients.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
cols | integer | No | Initial terminal width. Defaults to 80. |
rows | integer | No | Initial terminal height. Defaults to 24. |
shell | string | No | Shell command. Defaults to login bash when available. |
Response — 201 Created
{
"session_id": "52d1df5a0a3a0018",
"ws_url": "wss://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/terminal/stream",
"stream_auth": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9...",
"stream_auth_expires_at": "2026-05-13T12:30:00Z"
} Open the WebSocket with:
wss://api.miosa.ai/api/v1/sandboxes/{id}/terminal/stream?session_id={session_id}&cols=120&rows=32&token={stream_auth} Clients should send raw terminal input as binary frames. Resize events are sent as JSON text frames:
{"type":"resize","cols":120,"rows":32} Delete the session when finished:
curl -X DELETE https://api.miosa.ai/api/v1/sandboxes/{id}/terminal/{session_id}
-H "Authorization: Bearer $MIOSA_API_KEY" Expose a Preview Port
POST /api/v1/sandboxes/{id}/expose
Returns a public, tenant-aware preview URL for a server running inside the sandbox. Use this when an agent generated a Vite/Next/FastAPI/Flask app and started it on a local port.
Inside the sandbox, bind dev servers to 0.0.0.0, not localhost:
npm run dev -- --host 0.0.0.0 --port 5173
python -m http.server 8000 --bind 0.0.0.0 Request Body
| Field | Type | Required | Description |
|---|---|---|---|
port | integer | No | Port inside the sandbox to expose. If omitted, MIOSA uses the template lifecycle preview port when available. Must be 1 through 65535 when provided. |
Response — 200 OK
{
"url": "https://5173-sbx01j9x.sandbox.miosa.app"
} If the tenant has a white-label preview domain configured, the same endpoint returns that domain instead of the platform default. Default app ports such as 3000, 5173, 8080, 8000, and 80 may be returned as https://{slug}.sandbox.{domain}; non-default ports use https://{port}-{slug}.sandbox.{domain}.
Errors
| Status | Code | Cause |
|---|---|---|
| 400 | MISSING_PARAM | port was omitted and the sandbox template has no default preview port. |
| 409 | SANDBOX_NOT_RUNNING | Sandbox is not in running state. |
| 422 | INVALID_PORT | Port is outside 1 through 65535. |
curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/expose
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"port": 5173}' For static artifacts such as PDFs, images, Markdown, CSV, or ZIP files, write them under /workspace and download them through the files API. For web apps, start a server and expose the port.
Promote a Sandbox to a Deployment
POST /api/v1/sandboxes/{id}/deploy
Promotes a running sandbox into a persistent deployment URL. This is the publish step for generated-app platforms: the sandbox remains the runtime behind the deployment route, its auto-destroy timer is cancelled, and the deployment is marked running against the sandbox VM IP and preview port.
Use this after your generated app is serving successfully through /template/start or /expose.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable deployment name. Used to create the deployment slug. |
port | integer | No | Runtime port to route. Defaults to the template lifecycle preview port, then 80. |
domain | string | No | Custom domain to attach. |
custom_domain | string | No | Alias for domain, used by frontend clients. |
Response — 201 Created
{
"deployment_id": "dep_01j9xr2t4fk8me3n5q",
"url": "https://my-app-a1b2c3.acme.miosa.app",
"state": "running"
} Managed deployment URLs are tenant-scoped: https://{deployment-slug}.{tenant-slug}.miosa.app. MIOSA persists the sandbox runtime target on the deployment and reconciles running routes, so a temporary proxy restart or admin API outage can be repaired from the database.
Errors
| Status | Code | Cause |
|---|---|---|
| 400 | MISSING_PARAM | name was omitted. |
| 409 | SANDBOX_NOT_RUNNING | Sandbox is not in running state. |
| 409 | SANDBOX_RUNTIME_UNAVAILABLE | Sandbox is marked running but has no VM IP yet. |
| 422 | INVALID_PORT | Port is outside 1 through 65535. |
| 422 | VALIDATION_ERROR | Deployment record validation failed. |
curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/deploy
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"name":"my-app","port":8000}' Upload a File
POST /api/v1/sandboxes/{id}/files
Writes a file to the sandbox filesystem. Two request formats are accepted.
Auth
Bearer token required.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Sandbox ID. Must be in running state. |
Request Body — JSON
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Absolute destination path inside the sandbox. |
content | string | Yes | Base64-encoded file content. |
{
"path": "/workspace/script.py",
"content": "cHJpbnQoJ2hlbGxvJyk="
} Request Body — Multipart
Alternatively, send multipart/form-data with fields:
| Field | Description |
|---|---|
path | Absolute destination path. |
file | File part containing the raw content. |
Response — 200 OK
{
"data": {
"sandbox_id": "sbx_01j9xr2t4fk8me3n5q",
"path": "/workspace/script.py",
"size": 16
}
} Errors
| Status | Code | Cause |
|---|---|---|
| 409 | SANDBOX_NOT_RUNNING | Sandbox is not in running state. |
| 413 | — | File exceeds the 100 MB upload limit. |
# JSON (base64-encoded content)
curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/files
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d "{"path": "/workspace/script.py", "content": "$(base64 -w0 script.py)"}"
# Multipart
curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/files
-H "Authorization: Bearer $MIOSA_API_KEY"
-F "path=/workspace/script.py"
-F "file=@script.py" Download a File
GET /api/v1/sandboxes/{id}/files/{path}
Downloads a file from the sandbox filesystem.
Auth
Bearer token required.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Sandbox ID. Must be in running state. |
path | string | URL-encoded path to the file inside the sandbox (leading / stripped). |
Response — 200 OK
Raw file bytes with Content-Type: application/octet-stream.
Errors
| Status | Code | Cause |
|---|---|---|
| 404 | FILE_NOT_FOUND | Path does not exist inside the sandbox. |
| 409 | SANDBOX_NOT_RUNNING | Sandbox is not in running state. |
curl -o output.json
"https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/files/workspace%2Foutput.json"
-H "Authorization: Bearer $MIOSA_API_KEY" List Files
GET /api/v1/sandboxes/{id}/files?path=/workspace
Lists files and directories in a sandbox directory.
curl "https://api.miosa.ai/api/v1/sandboxes/{id}/files?path=/workspace"
-H "Authorization: Bearer $MIOSA_API_KEY" Response:
{
"data": {
"path": "/workspace",
"entries": [
{"name": "index.html", "path": "/workspace/index.html", "is_dir": false, "size": 128}
]
}
} Stat a File
POST /api/v1/sandboxes/{id}/files/stat
Returns metadata for one file or directory.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/files/stat
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"path":"/workspace/index.html"}' Read Logs
GET /api/v1/sandboxes/{id}/logs
Returns recent sandbox/template lifecycle logs. Pass lines to control the
tail length.
curl "https://api.miosa.ai/api/v1/sandboxes/{id}/logs?lines=200"
-H "Authorization: Bearer $MIOSA_API_KEY" Stream logs with SSE:
curl -N "https://api.miosa.ai/api/v1/sandboxes/{id}/logs/stream"
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Accept: text/event-stream" Snapshot Lifecycle
POST /api/v1/sandboxes/{id}/snapshots
Creates a named checkpoint for a running sandbox.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/snapshots
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"comment":"before dependency upgrade"}' List, inspect, restore, and delete snapshots:
curl https://api.miosa.ai/api/v1/sandboxes/{id}/snapshots
-H "Authorization: Bearer $MIOSA_API_KEY"
curl https://api.miosa.ai/api/v1/sandboxes/{id}/snapshots/{snapshot_id}
-H "Authorization: Bearer $MIOSA_API_KEY"
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/restore/{snapshot_id}
-H "Authorization: Bearer $MIOSA_API_KEY"
curl -X DELETE https://api.miosa.ai/api/v1/sandboxes/{id}/snapshots/{snapshot_id}
-H "Authorization: Bearer $MIOSA_API_KEY" Pause and Resume
POST /api/v1/sandboxes/{id}/pause
Pauses a running sandbox using the Firecracker snapshot path. Paused sandboxes keep their lifecycle record and can be resumed.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/pause
-H "Authorization: Bearer $MIOSA_API_KEY"
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/resume
-H "Authorization: Bearer $MIOSA_API_KEY" Subscribe to Events (SSE)
GET /api/v1/sandboxes/{id}/events
Opens a Server-Sent Events (SSE) stream that emits sandbox lifecycle events. The connection closes automatically when the sandbox reaches destroyed or error.
Auth
Bearer token required (sent as Authorization: Bearer <key> header).
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Sandbox ID. |
Response — 200 OK (event stream)
Content-Type: text/event-stream
Event: state_changed
event: state_changed
data: {"state":"running","previous_state":"provisioning","timestamp":"2026-04-25T10:00:07Z"} Event: exec_output
event: exec_output
data: {"exec_id":"exec_abc","stream":"stdout","data":"2\n","timestamp":"2026-04-25T10:00:10Z"} Event: error
event: error
data: {"message":"VM terminated unexpectedly","timestamp":"2026-04-25T10:05:00Z"} curl -N "https://api.miosa.ai/api/v1/sandboxes/sbx_01j9xr2t4fk8me3n5q/events"
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Accept: text/event-stream" Sandbox Object
The full sandbox object returned by create, get, and list endpoints:
| Field | Type | Description |
|---|---|---|
id | string | Unique sandbox identifier. |
tenant_id | string | Owning tenant ID. |
owner_id | string | Creating user ID. |
template_id | string | Boot template name. |
state | string | Current lifecycle state. |
cpu_count | integer | Allocated vCPUs. |
memory_mb | integer | Allocated RAM in MB. |
disk_size_mb | integer | Allocated root disk in MB. |
image_id | string | Resolved rootfs image, for example miosa-sandbox. |
boot_path | string/null | Boot mechanism used, for example snapshot or cold. |
boot_ms | integer/null | Runtime boot time in milliseconds once known. |
ready | boolean | Whether envd and readiness checks are accepting work. |
ready_at | string/null | ISO timestamp when ready became true. |
preview_url | string/null | Tenant-aware base preview URL for the sandbox slug. Use /expose for a specific port. |
timeout_sec | integer | Max seconds before force-destroy. |
total_runtime_sec | integer | null | Billed seconds. Set only after destruction. |
metadata | object | Caller-supplied metadata. |
created_at | string | ISO-8601 creation timestamp. |
started_at | string | null | ISO-8601 timestamp when VM entered running. |
destroyed_at | string | null | ISO-8601 timestamp when VM was destroyed. |
Lifecycle States
provisioning → running → destroyed
running → paused → running
* → error (terminal) | State | Description |
|---|---|
provisioning | VM is booting. Exec and file operations are not yet available. |
running | VM is reachable. All operations allowed. |
paused | VM has a RAM snapshot on disk. Can be resumed. |
destroyed | Terminal. VM is gone, billing is settled. |
error | Terminal failure. Destroy and create a new sandbox. |
Error Response Format
All error responses use this shape:
{
"error": {
"code": "NOT_FOUND",
"message": "sandbox not found",
"details": null
}
} The x-request-id response header is set on every request. Include it in support requests.
Rate Limits
| Limit | Value |
|---|---|
| Requests per minute per workspace | 300 |
| Concurrent sandboxes per tenant | 10 (contact support to increase) |
| Max sandbox runtime | Plan/policy dependent; day-long and always-on sandboxes are supported when billing policy allows it |
| Default resource shape | 1 vCPU, 1 GB RAM, 3 GB disk |
| Default resource caps | 4 vCPU, 8 GB RAM, 10 GB disk |
| Max exec timeout | 300 s (5 minutes) |
| Max file upload size | 100 MB |
Rate-limited responses return HTTP 429 with a Retry-After header indicating seconds to wait.
See also
- Python SDK —
miosa - TypeScript SDK —
@miosa/sdk - Go SDK —
github.com/miosa-ai/miosa-go - Java SDK —
ai.miosa:miosa-sdk - Elixir SDK —
:miosa - Events (SSE) — SSE reference for other MIOSA resources
- Error Codes — full error code catalog including sandbox-specific codes