Sandboxes are persistent-by-default isolated microVM workspaces that restore from pre-seeded snapshots, 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 and sizes
GET /api/v1/templates
This is the canonical catalog for sandbox template IDs, template defaults, per-template size support, readiness, and exact versioned resource contracts. Clients need no secondary catalog endpoint to discover or admit a sandbox configuration.
curl https://api.miosa.ai/api/v1/templates Response - 200 OK
{
"data": [
{
"id": "miosa-sandbox",
"name": "MIOSA Sandbox",
"product": "sandbox",
"default_size": "small",
"primitive": "sandbox",
"sdk_name": "miosa-sandbox",
"cli_name": "miosa-sandbox",
"readiness": "fast_ready",
"sizes": [
{
"size": "small",
"state": "fast_ready",
"resource_contract": {
"contract_id": "sandbox/small@v1",
"contract_version": "v1",
"product": "sandbox",
"size": "small",
"vcpus": 2,
"memory_mb": 4096,
"disk_size_mb": 10240
}
}
]
}
],
"templates": [
{
"id": "miosa-sandbox",
"name": "MIOSA Sandbox",
"product": "sandbox",
"default_size": "small",
"primitive": "sandbox",
"sdk_name": "miosa-sandbox",
"cli_name": "miosa-sandbox",
"readiness": "fast_ready",
"sizes": [
{
"size": "small",
"state": "fast_ready"
}
]
}
],
"shape_contracts": {
"sandbox": [],
"computer": []
},
"readiness_states": ["fast_ready", "cold_boot_only", "missing"]
} fast_ready sizes are creatable through the fast start path. cold_boot_only sizes are also creatable but start more slowly. missing means unavailable and must not be submitted.
Use that template’s default_size when the caller does not have a stronger requirement.
Do not combine a size advertised by one template with another template.
Custom templates
The canonical public V1 contract exposes only promoted templates returned by GET /api/v1/templates.
Standalone custom-template build, validation, log, retry, and cancellation endpoints are not part of that contract.
Do not make a public integration depend on those operations.
Configuration and request parameters
GET /api/v1/templates returns platform configuration: available templates, the default size, readiness, and versioned resource contracts.
Applications select that configuration with sandbox parameters; they do not send internal host, provider, network, or placement fields.
Prefer size for create requests.
The default small contract is 2 vCPU, 4096 MiB RAM, and 10240 MiB disk. xs is selectable when the catalog reports it as available.
Compatibility resource fields must include cpu_count, memory_mb, and disk_size_mb together and exactly match one published contract.
Responses include the resolved contract under resource_contract.
Contract IDs are versioned, for example sandbox/small@v1; persist that identity when usage or audit records must remain reproducible.
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 production alias miosa-sandbox resolves to a certified immutable artifact generation.
See Benchmarks for guarded production evidence and methodology.
Auth
Bearer token required.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | No | Boot template. Defaults to miosa-sandbox. See available templates below. |
size | string | No | Canonical resource configuration. Defaults to small (2 vCPU, 4096 MiB, 10240 MiB disk). |
cpu_count | integer | No | Exact vCPU compatibility input. Supply the full matching resource triple. |
memory_mb | integer | No | Exact RAM override. It must match the selected canonical size. |
disk_size_mb | integer | No | Exact disk override. It must match the selected canonical size. disk_mb is deprecated. |
timeout_sec | integer | No | Active-session timeout. Defaults to 3600; minimum 1, maximum 86400. |
always_on | boolean | No | Disable timeout and idle-timeout enforcement until an explicit lifecycle action. Defaults to false and remains subject to policy. |
persistent | boolean | No | Defaults to true. Preserve filesystem state across stop/timeout and allow resume. Set false only for disposable one-off jobs. |
idle_timeout_sec | integer | No | Seconds without activity before auto-stop. 0, the default, disables idle timeout. |
env | object | No | Key-value env vars injected at boot. |
metadata | object | No | Arbitrary caller-supplied metadata stored on the record. |
agent_runtime_profile_id | UUID/string | No | Force a specific agent runtime profile for this sandbox. Alias: agent_profile_id. |
skip_agent_runtime_profile | boolean | No | If true, do not apply the tenant/workspace default runtime profile. |
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. |
If a default agent runtime profile exists for the workspace or tenant, MIOSA
applies it automatically during create. Profile env vars are merged with request
env vars, request env wins on conflict, profile metadata is recorded under metadata.agent_runtime_profile, and profile connectors are attached through
egress placeholder tokens rather than copied as plaintext secrets.
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,
"size": "small",
"resource_contract": {
"id": "sandbox/small@v1",
"product": "sandbox",
"size": "small",
"version": "v1",
"vcpus": 2,
"memory_mb": 4096,
"disk_size_mb": 10240
},
"cpu_count": 2,
"memory_mb": 4096,
"disk_size_mb": 10240,
"preview_url": "https://sbx01j9x.sandbox.miosa.ai",
"timeout_sec": 3600,
"timeout_remaining_ms": null,
"always_on": false,
"persistent": true,
"idle_timeout_sec": 0,
"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). |
Create and Run
POST /api/v1/sandboxes/run
Creates a sandbox, waits for it to become running, executes the first command, and returns the sandbox record plus the command result in one request. Use this for agent loops where the first useful action is “create a sandbox and run code now.”
This is the production fast path used by MIOSA’s sandbox benchmark. Performance claims are published only from guarded create-to-command cohorts that also hold the peak live set and prove zero-residue teardown.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/run
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-H "Idempotency-Key: run-2026-06-09-001"
-d '{
"template_id": "miosa-sandbox",
"command": "python3 -c "print(1+1)"",
"size": "small",
"timeout_sec": 300,
"wait_timeout_ms": 30000,
"metadata": { "agent_run": "abc123" }
}' Request Body
/run accepts the same sandbox creation fields as POST /api/v1/sandboxes, plus:
| Field | Type | Required | Description |
|---|---|---|---|
command | string | Yes | First command to execute after the sandbox reaches running. |
cwd | string | No | Working directory for the command. Defaults to /workspace. |
timeout | integer | No | Command timeout in milliseconds. |
wait_timeout_ms | integer | No | Max time to wait for sandbox readiness before returning 504 SANDBOX_READY_TIMEOUT. |
Response - 201 Created
{
"data": {
"id": "sbx_01j9xr2t4fk8me3n5q",
"state": "running",
"ready": true,
"template_id": "miosa-sandbox",
"cpu_count": 2,
"memory_mb": 4096
},
"exec": {
"stdout": "2\n",
"stderr": "",
"exit_code": 0
},
"timings": {
"server_wait_and_exec_ms": 512
}
} Errors
| Status | Code | Cause |
|---|---|---|
| 400 | MISSING_PARAM | command is missing. |
| 400 | INVALID_TEMPLATE | template_id is not recognized. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits to provision the VM. |
| 409 | SANDBOX_LIMIT_EXCEEDED | Tenant has reached the concurrent sandbox limit. |
| 409 | SANDBOX_NOT_RUNNING | The sandbox failed to reach a running state for exec. |
| 502 | SANDBOX_BOOT_FAILED | VM boot failed before the command could run. |
| 502 | AGENT_UNAVAILABLE | The sandbox agent was not reachable for exec. |
| 504 | SANDBOX_READY_TIMEOUT | The sandbox did not become ready before wait_timeout_ms. |
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.ai",
"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",
"size": "small",
"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": 2,
"memory_mb": 4096,
"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}
Permanently deletes the sandbox, removes saved state, and settles billing. Use POST /pause when the user is done for now but may resume later.
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" Export Files
Exports are for files an agent created inside the sandbox that your product needs to show or download: static HTML, PDFs, CSVs, screenshots, generated reports, ZIPs, and build folders.
POST /api/v1/sandboxes/{id}/exports
Creates a ready export descriptor. This does not move the file out of the sandbox; it returns download URLs backed by the sandbox filesystem.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes, unless paths is set | Single file path inside the sandbox. |
paths | array | Yes, unless path is set | Multiple file paths to package as a tar.gz archive. |
label | string | No | Human-readable export label. |
filename | string | No | Suggested filename for download responses. |
Response - 200 OK
{
"data": {
"id": "exp_01j9xr2t4fk8me3n5q",
"sandbox_id": "sbx_01j9xr2t4fk8me3n5q",
"label": "homepage build",
"status": "ready",
"files": [
{
"path": "/workspace/dist/index.html",
"filename": "index.html",
"download_url": "https://api.miosa.ai/api/v1/sandboxes/sbx_.../exports/download?path=..."
}
],
"archive_download_url": "https://api.miosa.ai/api/v1/sandboxes/sbx_.../exports/download?paths%5B%5D=...",
"created_at": "2026-06-14T21:00:00Z"
}
} GET /api/v1/sandboxes/{id}/exports/download?path=/workspace/report.pdf
Downloads one file as binary.
GET /api/v1/sandboxes/{id}/exports/download?paths[]=/workspace/dist/index.html&paths[]=/workspace/dist/app.js
Downloads multiple paths as a tar.gz archive.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/$SBX/exports
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"paths":["/workspace/dist/index.html","/workspace/dist/app.js"],"label":"build"}'
curl "https://api.miosa.ai/api/v1/sandboxes/$SBX/exports/download?path=/workspace/report.pdf"
-H "Authorization: Bearer $MIOSA_API_KEY"
-o report.pdf 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.ai"
} 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.
Publish a Sandbox
POST /api/v1/sandboxes/{id}/publish
Freezes sandbox source, creates an immutable release and deployment version, verifies the candidate, and promotes it behind a stable deployment URL. Use this endpoint for production publishing.
The CLI is the recommended happy path:
miosa sandbox publish <sandbox-id>
--app <deployment-id>
--docker-deploy
--wait
--json Omit --app for the first publish.
Include it for updates so MIOSA preserves the deployment ID and canonical URL.
See Publishing for request options, proof, and failure behavior.
Promote a Sandbox Runtime to a Deployment
POST /api/v1/sandboxes/{id}/deploy
This compatibility bridge routes a persistent deployment URL directly to a running sandbox. The sandbox remains the runtime behind the route and its auto-destroy timer is cancelled.
Use it only when the sandbox itself must remain the runtime.
For immutable production versions and App Engine, use /publish.
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" Extend the Timeout
POST /api/v1/sandboxes/{id}/extend
Replaces the active-session timeout with timeout_sec from 1 through 86400.
The operation does not add duration to the old value.
Omitting the body preserves the current timeout.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/extend
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{"timeout_sec":7200}' Get Sandbox Usage
GET /api/v1/sandboxes/{id}/usage
Returns measured runtime, provisioned vCPU time, active CPU, network traffic, estimated cost, and timeout visibility.
{
"data": {
"sandbox_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "running",
"runtime_sec": 47,
"provisioned_vcpu_ms": 94000,
"active_cpu_ms": 12000,
"network_ingress_bytes": 2048,
"network_egress_bytes": 4096,
"measurement_status": {
"active_cpu": "measured",
"network": "measured",
"provisioned_resources": "measured"
},
"estimated_cost_cents": 1,
"timeout_sec": 3600,
"timeout_remaining_ms": 3553000
}
} Interpret nullable measurements through measurement_status. unavailable means no trustworthy value exists and the related field is null, not zero. stale means the retained value is not current and must be labeled as such. timeout_remaining_ms can be null before start or when timeout enforcement is disabled.
Pause and Resume
POST /api/v1/sandboxes/{id}/pause suspends guest vCPU execution for a running persistent sandbox while preserving its workspace.
It returns 409 if the sandbox is not running.
POST /api/v1/sandboxes/{id}/resume transitions a paused sandbox back to running and returns 409 if it is not paused.
Command and file operations can automatically resume a paused persistent sandbox before dispatch.
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"
-H "Idempotency-Key: resume-session-001" Fork a Sandbox
POST /api/v1/sandboxes/{id}/fork creates a new sandbox from a copy-on-write snapshot of a running sandbox.
The optional body accepts timeout_sec and template_id for the new sandbox.
curl -X POST https://api.miosa.ai/api/v1/sandboxes/{id}/fork
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-H "Idempotency-Key: fork-experiment-001"
-d '{"timeout_sec":3600}' Canonical public V1 exposes standalone snapshot create, list, inspect, delete, and restore operations. Use fork when a customer needs an independent branch of current running state without managing the intermediate snapshot directly.
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. |
size | string | Canonical named size: xs, small, medium, large, or xl. |
resource_contract | object | Versioned resolved contract with ID, product, size, vCPU, memory, and disk. |
cpu_count | integer | Allocated vCPUs. |
memory_mb | integer | Allocated RAM in MB. |
disk_size_mb | integer | Allocated root disk in MB. |
ready | boolean | Whether command 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 for the active session. Persistent timeout pauses; non-persistent timeout destroys. |
timeout_remaining_ms | integer | null | Remaining active-session time; null before start or when timeout enforcement is disabled. |
always_on | boolean | Whether timeout and idle-timeout enforcement are disabled. |
persistent | boolean | Whether the sandbox preserves filesystem state across stop/timeout. |
idle_timeout_sec | integer | Seconds without activity before auto-stop; zero disables it. |
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 → paused
running → paused → running
running → destroyed
* → error (terminal) | State | Description |
|---|---|
provisioning | VM is booting. Exec and file operations are not yet available. |
running | VM is reachable. All operations allowed. |
paused | Compute is stopped and filesystem state is preserved. 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 |
|---|---|
| Request rate | Returned through X-RateLimit-* headers; varies by key and policy |
| Concurrent sandboxes per tenant | 10 (contact support to increase) |
timeout_sec | 1-86400 seconds; default 3600 |
| Default resource shape | small: 2 vCPU, 4 GiB RAM, 10 GiB disk |
| Named resource schema | xs through xl; actual availability comes from GET /templates and tenant policy |
| 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