Fundamental Concepts
MIOSA is a cloud platform for building and deploying applications. Before writing your first API call, read this page. It covers the eight concepts that underpin every MIOSA integration.
1. Organization, workspaces, and projects
Your MIOSA account starts as one organization. The organization has a permanent slug, one billing account, and API keys. Inside it, you can create multiple workspaces and projects:
- The organization is the authorization and billing boundary.
- A workspace usually represents a customer, client, team, or environment.
- A project represents the app, website, lead magnet, document, or workflow being built inside a workspace.
- Sandboxes, Computers, Deployments, Databases, Domains, Storage, Volumes, Functions, and Jobs belong to a project.
If you are building a platform product on top of MIOSA, use MIOSA workspaces for downstream customers and MIOSA projects for the things they create. External attribution fields still exist for your own IDs and chargeback.
2. Authentication
Every API request carries one header:
Authorization: Bearer <token> The token is either an API key or a browser token (scoped JWT).
API keys
API keys have the prefix msk_ followed by a role segment:
| Prefix | Role | Use |
|---|---|---|
msk_u_... | user | General-purpose server-side calls |
msk_a_... | admin | Operator/platform tooling |
msk_p_... | platform | Tenant-wide automation |
API keys are server-side only. Never put an msk_* key in browser code, a mobile app, or a public repository.
Browser tokens
For browser-side access - embedding a preview, opening a terminal in an iframe - your backend mints a short-lived scoped token and passes it to the client:
Browser tokens expire, are non-renewable, and are scoped to a single resource. They cannot create new resources.
See Authentication and Browser Tokens for the full reference.
3. Ownership and external attribution
Every MIOSA resource accepts canonical ownership fields and optional attribution fields:
| Field | Meaning |
|---|---|
workspace_id / workspace_slug | The MIOSA workspace that owns the resource |
project_id / project_slug | The MIOSA project that owns the resource |
external_workspace_id | Your customer’s account / tenant ID |
external_user_id | The end-user inside that account |
external_project_id | The project or app ID in your own database |
Every resource also accepts a free-form metadata object (up to 16 key-value string pairs). Use it to carry application-layer context - feature flags, plan tier, region, whatever your billing system needs - without bloating your own database with a MIOSA resource join.
Integrators use these fields for four main purposes:
- Usage rollup - query
GET /api/v1/sandboxes?external_workspace_id=acme-coto aggregate compute time and costs for a downstream customer. - Per-end-user quotas - enforce your own rate limits by counting active sandboxes per
external_user_idbefore creating a new one. - Audit log filtering - the audit log accepts
external_user_idandexternal_project_idas filters so you can pull a customer-specific activity trail without exposing other customers’ data. - Chargeback and billing -
external_workspace_idis the recommended key for billing rollup when you resell MIOSA compute to downstream customers. See the Audit Log and Quotas references.
MIOSA stores canonical workspace_id and project_id on each resource. The external fields are stored as opaque strings. Both appear on list/read responses, and list endpoints accept them as filters:
Filtering is always scoped to your MIOSA organization. You cannot see another organization’s resources regardless of what workspace, project, or external IDs you pass.
See Ownership and Attribution for the full filter spec and billing split by workspace/project.
4. The six resources
Every MIOSA operation creates, reads, updates, or destroys one of these six types.
A mutable microVM where agents or developers build an app. Execute commands, read and write files, run dev servers, take snapshots.
A temporary public URL that tunnels to a port inside a running sandbox. Safe to embed in an iframe with a browser token.
The stable product object the world knows as “the live app.” Holds an active_version_id. Publishing creates a new Version; rollback resets it.
An immutable snapshot of a built Release attached to a Deployment. Promoting a Version updates live traffic. Prior Versions stay available for rollback.
A production microVM booted from a dynamic Release. The scheduler places, scales, and health-checks instances automatically.
A DNS hostname routed to a Deployment’s active Version. Supports MIOSA-managed subdomains and custom domains with auto-provisioned TLS.
The publish pipeline connects them in order:
Sandbox → Builder → Release → Version → Deployment → Domain A Builder is an internal ephemeral VM that runs the build. You never address it directly.
5. Token types
MIOSA issues five distinct token types. Each covers a different caller and trust level:
| Token | Prefix | Caller | TTL | Read / Write |
|---|---|---|---|---|
| API key | msk_* | Your server | Until revoked | Read + Write |
| JWT | ey... | Admin UI / browser session | ~1 h (refresh 7 d) | Read + Write |
| Browser token | (opaque) | Your user’s browser | Configurable (default 1 h) | Read-only, single resource |
| Preview token | mp_* | Browser / <MiosaPreview> iframe | Configurable (default 1 h) | Read-only, sandbox preview |
| Share token | ms_* | Anyone - no account required | Configurable | Read-only, sandbox preview |
The msk_* API key is the root credential. All other token types are minted downstream from it by your server. Never give an msk_* key to a browser or end user.
For minting flows, revocation, and validation rules see Authentication and Preview Tokens.
7. Idempotency
Every mutation endpoint (POST, PUT, PATCH, DELETE) accepts an optional Idempotency-Key header. Retrying a request with the same key is safe - MIOSA returns the original response without re-executing the operation.
POST /api/v1/sandboxes
Authorization: Bearer msk_u_...
Idempotency-Key: create-sandbox-for-alice-2026-05-17
Content-Type: application/json
{ "template_id": "miosa-sandbox", "external_user_id": "alice" } Idempotency keys are:
- Scoped to your workspace and the endpoint path.
- Valid for 24 hours from first use.
- Stored regardless of whether the original request succeeded or failed.
If the first request timed out before you received a response, retry with the same key. You will receive the original result if the operation completed, or a 202 Accepted if it is still in progress.
8. Rate limits
Rate limits apply per API key, per workspace, and per endpoint family. Every response includes quota headers:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1748390460 Default limits:
| Endpoint family | Limit | Window |
|---|---|---|
GET /api/v1/* (reads) | 600 requests | Per minute per key |
POST /PUT /PATCH /DELETE /api/v1/* (writes) | 300 requests | Per minute per key |
Auth (/auth/login, /auth/refresh) | 60 requests | Per minute per IP |
When you exceed a limit, the API returns 429 Too Many Requests with a Retry-After header containing the number of seconds until your quota resets.
High-volume workloads (AI agent pipelines creating many sandboxes per minute) can request a quota increase from the platform dashboard or by contacting support.
9. Tenant-level configuration
White-label integrators can configure four areas of tenant behavior via the API. All routes accept msk_a_* admin keys or admin JWTs.
Preview domain
Map a custom subdomain (e.g., preview.yourdomain.com) to sandbox preview URLs. Once set, the MIOSA router serves sandbox previews on your domain instead of *.miosa.app. Configure DNS with a CNAME to sandbox.miosa.app, then register the domain:
PUT /api/v1/tenant/preview-domain
{ "domain": "preview.yourdomain.com" } Branding
Customize the 404 and 502 error pages shown inside sandbox previews and deployments. Accepts an HTML template with {{status}} and {{message}} interpolation slots:
PUT /api/v1/tenant/branding
{ "error_page_html": "<html>...</html>", "logo_url": "https://..." } See Tenant Branding.
Webhooks
Subscribe to sandbox and deployment lifecycle events delivered as HTTPS POST requests to your endpoint. MIOSA signs each request with an HMAC-SHA256 signature in the X-Miosa-Signature header:
POST /api/v1/tenant/webhooks
{ "url": "https://yourapp.com/webhooks/miosa", "events": ["sandbox.*", "deployment.*"] } See Webhooks and Integrations for the event catalog and signature verification.
Per-end-user quotas
Set maximum resource counts per external_user_id to prevent runaway usage by a single downstream user. Quotas are checked at resource creation time and return 429 with code QUOTA_EXCEEDED when reached:
PUT /api/v1/tenant/quotas
{ "max_sandboxes_per_user": 5, "max_computers_per_user": 2 } See Quotas.
10. Errors
All errors use a consistent envelope:
{
"error": {
"code": "SANDBOX_NOT_FOUND",
"message": "No sandbox with id sbx_abc123 exists in this workspace.",
"request_id": "req_01hx9z..."
}
} | Field | Description |
|---|---|
code | Machine-readable constant. Use this in your switch statements, not message. |
message | Human-readable explanation. May change between API versions. |
request_id | Include this when contacting support or filing a bug report. |
HTTP status codes map directly to error categories:
| Status | Category |
|---|---|
400 | Invalid request body or parameters |
401 | Missing or invalid credential |
403 | Valid credential, insufficient permissions |
404 | Resource not found (or not visible to your workspace) |
409 | Conflict - resource already exists, duplicate idempotency key with different body |
422 | Validation error - request parsed correctly but failed domain rules |
429 | Rate limited |
5xx | MIOSA-side fault - safe to retry with exponential backoff |
The full error code catalog is in the API Reference.
10. Events (SSE)
Several long-running operations stream progress over Server-Sent Events. The SSE stream for a resource is always at:
GET /api/v1/{resource-type}/{id}/events Because the browser EventSource API does not support custom headers, SSE endpoints use a one-time ticket for authentication instead of the Authorization header:
Event types vary by resource. Common event shapes:
// Build log line
{ "type": "log", "stream": "stdout", "data": "Installing dependencies...", "ts": 1748390460 }
// Status change
{ "type": "status_changed", "previous": "building", "current": "ready", "ts": 1748390462 }
// Error
{ "type": "error", "code": "BUILD_FAILED", "message": "Exit code 1", "ts": 1748390465 } Sandbox lifecycle events
| Event | When |
|---|---|
sandbox.created | Sandbox resource created (not yet booted) |
sandbox.ready | Boot complete, exec and file endpoints available |
sandbox.error | Fatal boot or runtime error |
sandbox.destroyed | Sandbox stopped and resources released |
sandbox.share.created | A share token was minted for the sandbox |
sandbox.share.revoked | A share token was revoked |
Deployment lifecycle events
| Event | When |
|---|---|
deployment.created | Deployment object created |
deployment.build_started | Builder VM booted, build in progress |
deployment.build_succeeded | Release artifact ready |
deployment.build_failed | Build exited non-zero |
deployment.published | Active version updated, traffic cut over |
deployment.rollback | Active version reset to a prior version |
Tenant-wide SSE stream
To receive all lifecycle events for your organization without polling per-resource endpoints, subscribe to the tenant stream:
# Mint a ticket
TICKET=$(curl -s -X POST https://api.miosa.ai/api/v1/events/ticket
-H "Authorization: Bearer msk_u_..." | jq -r '.ticket')
# Stream all org events
curl -N "https://api.miosa.ai/api/v1/events?ticket=$TICKET" Each event on the tenant stream includes a resource_type and resource_id field so you can route to the right handler:
{
"type": "sandbox.ready",
"resource_type": "sandbox",
"resource_id": "sbx_abc123",
"external_user_id": "alice@acme.com",
"ts": 1748390462
} See Events (SSE) API Reference and Tenant Events for the complete event catalog and filtering options.
11. Sandboxes vs Computers
Two products, one platform. Pick based on what your workflow needs:
| Sandbox | Computer | |
|---|---|---|
| Primary use | Code execution, file I/O, dev servers, agent build loops | Desktop GUI, browser automation, screen-driven agents |
| Display | Headless (no screen) | X11 + VNC stream |
| Accessibility tree | No | Yes |
| APIs | exec, file I/O, snapshots, previews | screenshot, click, type, keyboard, scroll |
| Lifecycle | Short-to-medium, auto-suspend on idle | Session-oriented |
| Typical agent task | “Write and deploy a FastAPI service” | “Fill out this web form”, “navigate a GUI app” |
Use a Sandbox when your agent needs to write code, run shell commands, manage files, or serve a dev server.
Use a Computer when your agent needs to operate a graphical interface - a browser, a desktop app, or anything with a visible screen.
Both products live in the same organization, can be separated by workspace/project, and appear on the same billing account.