On this page

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:

CodeMeaning
REQUIREDA required field such as from is missing.
UNSUPPORTED_BASE_IMAGEAlpine/distroless bases are rejected for public agent templates.
OUT_OF_RANGEResource values are outside tenant-safe defaults.
INVALID_INTEGERNumeric fields are not integers.
INVALID_PORTPreview port is outside 1..65535.
INVALID_PATHWorkdir or artifact path is not absolute.
INVALID_STEPA 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

FieldTypeDescription
fromstringOCI base image. Debian/Ubuntu/Bookworm bases are recommended.
vcpuintegerTemplate-owned vCPU count.
memoryMibintegerTemplate-owned memory in MiB.
diskMibintegerTemplate-owned root disk in MiB.
stepsarrayOrdered build steps. Each step may define run, workdir, or env.
envobjectRuntime-default environment variables.
workdirstringRuntime working directory. Defaults to /workspace.
userstringRuntime user. Defaults to root.
startCmdstringLong-running command used by /template/start.
readyCmdstringReadiness command for the started app.
previewPortintegerDefault preview port for /expose and template start.
artifactPathsarrayPaths 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

FieldTypeRequiredDescription
template_idstringNoBoot template. Defaults to miosa-sandbox. See available templates below.
cpu_countintegerNovCPU count. Default 1, default cap 4.
memory_mbintegerNoRAM in MB. Default 1024, default cap 8192.
disk_mbintegerNoDisk in MB. Default 3072, default cap 10240.
timeout_secintegerNoMax wall-clock seconds before force-destroy. Day-long/always-on use is available when billing and policy allow it.
envobjectNoKey-value env vars injected at boot.
metadataobjectNoArbitrary caller-supplied metadata stored on the record.
auto_startbooleanNoIf 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_idUUIDNoExisting MIOSA workspace that owns the sandbox. Defaults to the organization default workspace.
workspace_slugstringNoExisting or auto-created workspace slug.
workspace_namestringNoWorkspace display name if auto-created.
project_idUUIDNoExisting MIOSA project that owns the sandbox. Defaults to the workspace default project.
project_slugstringNoExisting or auto-created project slug inside the workspace.
project_namestringNoProject display name if auto-created.
external_workspace_idstringNoYour customer/account/workspace ID.
external_user_idstringNoYour end-user ID.
external_project_idstringNoYour project/app/document ID.

Available templates:

template_idDescription
miosa-sandboxStable production alias for the current sandbox image.
nextjsNext.js app preview profile.
vite-reactVite React app preview profile.
pythonPython script/artifact generation profile.
streamlitStreamlit data app preview profile.
gradioGradio ML/demo app preview profile.
static-htmlStatic HTML/CSS/JS preview profile.

Request Headers

HeaderDescription
Idempotency-KeyClient-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

StatusCodeCause
400INVALID_TEMPLATEtemplate_id is not a recognized template.
402INSUFFICIENT_CREDITSNot enough credits to provision the VM.
409SANDBOX_LIMIT_EXCEEDEDTenant has reached the concurrent sandbox limit (default 10).
422VALIDATION_ERRORInvalid 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

ParameterTypeDescription
workspace_idUUIDFilter to one MIOSA workspace
project_idUUIDFilter to one MIOSA project
external_workspace_idstringFilter by your customer/account ID
external_user_idstringFilter by your end-user ID
external_project_idstringFilter by your project/app/document ID
statestringFilter 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

ParameterTypeDescription
idstringSandbox ID.

Response — 200 OK

Full sandbox object (same shape as the create response with current state).

Errors

StatusCodeCause
404NOT_FOUNDSandbox 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

ParameterTypeDescription
idstringSandbox ID.

Response — 200 OK

{
  "id": "sbx_01j9xr2t4fk8me3n5q",
  "state": "destroyed",
  "total_runtime_sec": 42
}

Errors

StatusCodeCause
404NOT_FOUNDSandbox 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

ParameterTypeDescription
idstringSandbox ID. Must be in running state.

Request Body

FieldTypeRequiredDescription
commandstringYesShell command to execute.
timeoutintegerNoPer-command timeout in seconds. Default 30, max 300.
working_dirstringNoWorking directory inside the VM. Default /root.
envobjectNoEnv vars for this invocation only.

Response — 200 OK

{
  "data": {
    "sandbox_id": "sbx_01j9xr2t4fk8me3n5q",
    "stdout": "2\n",
    "stderr": "",
    "exit_code": 0
  }
}

Errors

StatusCodeCause
409SANDBOX_NOT_RUNNINGSandbox is not in running state.
504Command 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

FieldTypeRequiredDescription
colsintegerNoInitial terminal width. Defaults to 80.
rowsintegerNoInitial terminal height. Defaults to 24.
shellstringNoShell 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

FieldTypeRequiredDescription
portintegerNoPort 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

StatusCodeCause
400MISSING_PARAMport was omitted and the sandbox template has no default preview port.
409SANDBOX_NOT_RUNNINGSandbox is not in running state.
422INVALID_PORTPort 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

FieldTypeRequiredDescription
namestringYesHuman-readable deployment name. Used to create the deployment slug.
portintegerNoRuntime port to route. Defaults to the template lifecycle preview port, then 80.
domainstringNoCustom domain to attach.
custom_domainstringNoAlias 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

StatusCodeCause
400MISSING_PARAMname was omitted.
409SANDBOX_NOT_RUNNINGSandbox is not in running state.
409SANDBOX_RUNTIME_UNAVAILABLESandbox is marked running but has no VM IP yet.
422INVALID_PORTPort is outside 1 through 65535.
422VALIDATION_ERRORDeployment 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

ParameterTypeDescription
idstringSandbox ID. Must be in running state.

Request Body — JSON

FieldTypeRequiredDescription
pathstringYesAbsolute destination path inside the sandbox.
contentstringYesBase64-encoded file content.
{
  "path": "/workspace/script.py",
  "content": "cHJpbnQoJ2hlbGxvJyk="
}

Request Body — Multipart

Alternatively, send multipart/form-data with fields:

FieldDescription
pathAbsolute destination path.
fileFile part containing the raw content.

Response — 200 OK

{
  "data": {
    "sandbox_id": "sbx_01j9xr2t4fk8me3n5q",
    "path": "/workspace/script.py",
    "size": 16
  }
}

Errors

StatusCodeCause
409SANDBOX_NOT_RUNNINGSandbox is not in running state.
413File 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

ParameterTypeDescription
idstringSandbox ID. Must be in running state.
pathstringURL-encoded path to the file inside the sandbox (leading / stripped).

Response — 200 OK

Raw file bytes with Content-Type: application/octet-stream.

Errors

StatusCodeCause
404FILE_NOT_FOUNDPath does not exist inside the sandbox.
409SANDBOX_NOT_RUNNINGSandbox 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

ParameterTypeDescription
idstringSandbox 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:

FieldTypeDescription
idstringUnique sandbox identifier.
tenant_idstringOwning tenant ID.
owner_idstringCreating user ID.
template_idstringBoot template name.
statestringCurrent lifecycle state.
cpu_countintegerAllocated vCPUs.
memory_mbintegerAllocated RAM in MB.
disk_size_mbintegerAllocated root disk in MB.
image_idstringResolved rootfs image, for example miosa-sandbox.
boot_pathstring/nullBoot mechanism used, for example snapshot or cold.
boot_msinteger/nullRuntime boot time in milliseconds once known.
readybooleanWhether envd and readiness checks are accepting work.
ready_atstring/nullISO timestamp when ready became true.
preview_urlstring/nullTenant-aware base preview URL for the sandbox slug. Use /expose for a specific port.
timeout_secintegerMax seconds before force-destroy.
total_runtime_secinteger | nullBilled seconds. Set only after destruction.
metadataobjectCaller-supplied metadata.
created_atstringISO-8601 creation timestamp.
started_atstring | nullISO-8601 timestamp when VM entered running.
destroyed_atstring | nullISO-8601 timestamp when VM was destroyed.

Lifecycle States


provisioning → running → destroyed
running → paused → running
* → error  (terminal)
StateDescription
provisioningVM is booting. Exec and file operations are not yet available.
runningVM is reachable. All operations allowed.
pausedVM has a RAM snapshot on disk. Can be resumed.
destroyedTerminal. VM is gone, billing is settled.
errorTerminal 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

LimitValue
Requests per minute per workspace300
Concurrent sandboxes per tenant10 (contact support to increase)
Max sandbox runtimePlan/policy dependent; day-long and always-on sandboxes are supported when billing policy allows it
Default resource shape1 vCPU, 1 GB RAM, 3 GB disk
Default resource caps4 vCPU, 8 GB RAM, 10 GB disk
Max exec timeout300 s (5 minutes)
Max file upload size100 MB

Rate-limited responses return HTTP 429 with a Retry-After header indicating seconds to wait.


See also

Was this helpful?