On this page

The official Go SDK for MIOSA. Requires Go 1.21+. All methods accept a context.Context for cancellation and timeouts.

Install

go get github.com/Miosa-osa/miosa-go@v0.4.0

What’s new in v0.4.0

AreaWhat shipped
Sandbox lifecycleSandboxes.Update(), Sandboxes.PreviewToken(), Sandboxes.Fork()
Tenant preview domainTenant.GetPreviewDomain(), SetPreviewDomain(), VerifyPreviewDomain(), DeletePreviewDomain()
Tenant brandingTenant.GetBranding(), SetBranding(), DeleteBranding()
WebhooksWebhooks.Create/List/Get/Delete/Test()
Files advancedSandboxFiles.Tree(), WriteMany(), Watch()
Sandbox envSandboxEnv.List/Set/Delete()
ProcessesSandboxProcesses.Start/List/Get/Stop/Logs/Stream()
Templates + forkSandboxTemplates.*, Sandboxes.Fork()
Usage / quotasUsage.Get(), Quotas.Set/Get/Delete()
SharingSandboxShare.Create/List/Revoke()
Workspace membersWorkspaceMembers.*, WorkspaceInvites.*
Org invitesOrgInvites.*

First request

package main

import (
    "context"
    "fmt"

    miosa "github.com/Miosa-osa/miosa-go"
)

func main() {
    ctx := context.Background()
    client := miosa.NewClient("msk_live_...")

    // Create a sandbox, run a command, delete it
    sandbox, err := client.Sandboxes.Create(ctx, miosa.CreateSandboxInput{
        Name: "quick-exec",
    })
    if err != nil {
        panic(err)
    }

    result, err := client.Exec.Run(ctx, sandbox.ID, miosa.ExecParams{
        Command: "python3 -c 'print(1 + 1)'",
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(result.Output) // "2\n"

    _ = client.Sandboxes.Delete(ctx, sandbox.ID)
}

Configure

OptionEnv varDefaultDescription
apiKey (positional)MIOSA_API_KEY-Workspace key (msk_live_*)
WithBaseURL(u)-https://api.miosa.ai/api/v1API endpoint
WithTimeout(d)-60sPer-request timeout
WithMaxRetries(n)-3Automatic retries on 429 / 5xx
WithHTTPClient(hc)-default http.ClientCustom HTTP client
import (
    "time"
    miosa "github.com/Miosa-osa/miosa-go"
)

client := miosa.NewClient(
    "msk_live_...",
    miosa.WithBaseURL("https://api.miosa.ai/api/v1"),
    miosa.WithTimeout(60 * time.Second),
    miosa.WithMaxRetries(3),
)

Authentication

Keys are passed as Authorization: Bearer <key>. The SDK validates the key format at construction time.

import "os"

client := miosa.NewClient(os.Getenv("MIOSA_API_KEY"))

Error handling

Use errors.As to match typed errors:

import (
    "errors"
    "fmt"
    miosa "github.com/Miosa-osa/miosa-go"
)

_, err := client.Computers.Get(ctx, "nonexistent-id")
if err != nil {
    var notFound *miosa.NotFoundError
    var rateLimit *miosa.RateLimitError
    switch {
    case errors.As(err, &notFound):
        fmt.Println("Computer not found")
    case errors.As(err, &rateLimit):
        fmt.Printf("Rate limited  -  retry after %.0fs\n", rateLimit.RetryAfter)
    default:
        fmt.Println("Error:", err)
    }
}

Streaming events

stream, err := computer.Events.Subscribe(ctx, miosa.EventSubscribeOptions{
    Subscribe: []miosa.EventProducer{
        miosa.ProducerWindow,
        miosa.ProducerFile,
        miosa.ProducerProcess,
    },
    Paths: []string{"/workspace"},
})
if err != nil {
    panic(err)
}
defer stream.Close()

for ev := range stream.C {
    fmt.Printf("[%s] %v\n", ev.Type, ev.Payload)
}

The stream.C channel is closed when the connection closes or the context is cancelled.


Phase 1-5 API Reference

Sandbox lifecycle (Phase 1)

client.Sandboxes - *SandboxesService

// Create  -  full input struct
sandbox, err := client.Sandboxes.Create(ctx, miosa.CreateSandboxInput{
    Name:                "my-sandbox",
    Slug:                "acme-backend",
    ExternalUserID:      "usr_123",
    ExternalProjectID:   "proj_456",
    ExternalWorkspaceID: "ws_789",
    Metadata:            map[string]interface{}{"env": "staging"},
    TimeoutSec:          300,
    AlwaysOn:            false,
    IdempotencyKey:      uuid.NewString(),
})

sandbox, err = client.Sandboxes.Get(ctx, sandboxID)
list, err    := client.Sandboxes.List(ctx, miosa.SandboxListParams{State: "running"})
err          = client.Sandboxes.Delete(ctx, sandboxID)

// Update mutable fields
updated, err := client.Sandboxes.Update(ctx, sandboxID, miosa.UpdateSandboxInput{
    Name:      "updated-name",
    Slug:      "new-slug",
    TimeoutSec: 600,
    AlwaysOn:  true,
})

// Mint a short-lived preview token
token, err := client.Sandboxes.PreviewToken(ctx, sandboxID, miosa.PreviewTokenInput{
    ExpiresIn: 3600,
    Scope:     "read",
})
// token.Token, token.URL, token.ExpiresAt

// Fork from a snapshot or running sandbox
forked, err := client.Sandboxes.Fork(ctx, sandboxID, miosa.ForkSandboxInput{
    SnapshotID:     "snap_abc",
    Name:           "forked-sandbox",
    ExternalUserID: "usr_123",
})
FieldTypeDescription
NamestringDisplay name
SlugstringURL-safe identifier
ExternalUserIDstringWhite-label user attribution
ExternalProjectIDstringWhite-label project attribution
ExternalWorkspaceIDstringWhite-label workspace attribution
Metadatamap[string]interface{}Arbitrary key-value pairs
TimeoutSecintLifetime in seconds
AlwaysOnboolStay alive past idle timeout
IdempotencyKeystringDeduplication key for retries

Tenant preview domain (Phase 1)

client.Tenant - *TenantService

// Get current custom preview domain
info, err := client.Tenant.GetPreviewDomain(ctx)
// info.Domain, info.VerifiedAt, info.CnameTarget

// Set custom preview domain
updated, err := client.Tenant.SetPreviewDomain(ctx, "preview.acme.com")

// Trigger DNS verification
result, err := client.Tenant.VerifyPreviewDomain(ctx)
// result["verified"], result["target"], result["records"]

// Remove custom domain
err = client.Tenant.DeletePreviewDomain(ctx)

Tenant branding (Phase 1)

client.Tenant - *TenantService

// Get current branding
branding, err := client.Tenant.GetBranding(ctx)

// Set branding
updated, err := client.Tenant.SetBranding(ctx, miosa.BrandingData{
    ProductName:     "Acme AI",
    LogoURL:         "https://cdn.acme.com/logo.png",
    SupportURL:      "https://acme.com/support",
    SupportEmail:    "help@acme.com",
    PrimaryColor:    "#ff6600",
    BackgroundColor: "#ffffff",
})

// Reset to platform defaults
err = client.Tenant.DeleteBranding(ctx)

Webhooks (Phase 1)

client.Webhooks - *WebhooksService

// Create a webhook
wh, err := client.Webhooks.Create(ctx, miosa.CreateWebhookInput{
    URL:    "https://example.com/webhooks/miosa",
    Events: []string{"sandbox.created", "sandbox.ready", "sandbox.destroyed"},
})

list, err := client.Webhooks.List(ctx)
wh, err    = client.Webhooks.Get(ctx, whID)
err        = client.Webhooks.Delete(ctx, whID)
err        = client.Webhooks.Test(ctx, whID)

Supported events: sandbox.created, sandbox.ready, sandbox.destroyed, sandbox.error, computer.started, computer.stopped, computer.error

Files advanced (Phase 2)

client.SandboxFiles(sandboxID) - *SandboxFilesService

files := client.SandboxFiles(sandboxID)

// Recursive directory tree
tree, err := files.Tree(ctx, "/workspace", 5) // path, depth

// Batch file write
result, err := files.WriteMany(ctx, []miosa.WriteFileInput{
    {Path: "/workspace/app.go", ContentBase64: base64.StdEncoding.EncodeToString([]byte("package main"))},
})

// Watch for file-system changes (SSE channel)
events, err := files.Watch(ctx)
if err != nil {
    panic(err)
}
for ev := range events {
    fmt.Println(ev.Type, ev.Data)
}

Sandbox environment variables (Phase 2)

client.SandboxEnv(sandboxID) - *SandboxEnvService

env := client.SandboxEnv(sandboxID)

vars, err := env.List(ctx)
_, err     = env.Set(ctx, []miosa.EnvVar{{Key: "DATABASE_URL", Value: "postgres://..."}})
err        = env.Delete(ctx, "DATABASE_URL")

Processes (Phase 2)

client.SandboxProcesses(sandboxID) - *SandboxProcessesService

procs := client.SandboxProcesses(sandboxID)

// Start a long-running background process
proc, err := procs.Start(ctx, miosa.StartProcessInput{
    Command: "npm run dev",
    Env:     map[string]string{"NODE_ENV": "development"},
    Name:    "dev-server",
})

list, err := procs.List(ctx)
one, err   := procs.Get(ctx, proc.PID)
err        = procs.Stop(ctx, proc.PID)
logs, err  := procs.Logs(ctx, proc.PID, 100)

// Streaming process output (SSE channel)
stream, err := procs.Stream(ctx, proc.PID)
for ev := range stream {
    fmt.Print(ev.Data)
}

Usage and quotas (Phase 3)

client.Usage - client.Quotas

// Usage rollup
report, err := client.Usage.Get(ctx, miosa.UsageParams{
    ExternalUserID: "usr_123",
    GroupBy:        "external_user_id",
    Period:         "30d",
})

// Set per-user quotas
quota, err := client.Quotas.Set(ctx, "usr_123", miosa.QuotaInput{
    MaxSandboxes:    5,
    MaxConcurrent:   2,
    MaxStorageGB:    10,
    MaxCreditCents:  10000,
})

quota, err = client.Quotas.Get(ctx, "usr_123")
err        = client.Quotas.Delete(ctx, "usr_123")

Audit log (Phase 3)

client.AuditLog

var after string
for {
    page, err := client.AuditLog.List(ctx, miosa.AuditLogListParams{
        After: after,
        Limit: 50,
    })
    if err != nil {
        break
    }
    for _, entry := range page.Items {
        fmt.Println(entry.Action, entry.CreatedAt)
    }
    if page.NextCursor == "" {
        break
    }
    after = page.NextCursor
}

Sharing (Phase 4)

client.SandboxShare(sandboxID) - *SandboxShareService

share := client.SandboxShare(sandboxID)

// Create a public share URL (no API key required to access)
expiresIn := 3600
data, err := share.Create(ctx, miosa.CreateShareInput{
    ExpiresIn: &expiresIn,
    Scope:     "read",
})
// data.ShareID, data.ShareURL, data.ExpiresAt

shares, err := share.List(ctx)
err          = share.Revoke(ctx, shareID)

White-label integrator flow

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/google/uuid"
    miosa "github.com/Miosa-osa/miosa-go"
)

func main() {
    ctx := context.Background()
    client := miosa.NewClient(os.Getenv("MIOSA_API_KEY"))

    // 1. Configure tenant branding once
    client.Tenant.SetBranding(ctx, miosa.BrandingData{
        ProductName:  "Acme AI",
        LogoURL:      "https://cdn.acme.com/logo.png",
        PrimaryColor: "#ff6600",
    })

    // 2. Set and verify a custom preview domain
    client.Tenant.SetPreviewDomain(ctx, "preview.acme.com")
    client.Tenant.VerifyPreviewDomain(ctx)

    // 3. Register webhook
    client.Webhooks.Create(ctx, miosa.CreateWebhookInput{
        URL:    "https://api.acme.com/webhooks/miosa",
        Events: []string{"sandbox.created", "sandbox.ready", "sandbox.destroyed"},
    })

    // 4. Set per-user quotas
    client.Quotas.Set(ctx, "usr_dr_smith", miosa.QuotaInput{
        MaxSandboxes:  3,
        MaxConcurrent: 1,
    })

    // 5. Create a sandbox attributed to a user + project
    sandbox, err := client.Sandboxes.Create(ctx, miosa.CreateSandboxInput{
        Name:                "smile-dental",
        ExternalUserID:      "usr_dr_smith",
        ExternalProjectID:   "proj_landing_page",
        ExternalWorkspaceID: "ws_smile_dental",
        Metadata:            map[string]interface{}{"plan": "pro"},
        IdempotencyKey:      uuid.NewString(),
    })
    if err != nil {
        panic(err)
    }

    // 6. Write files
    import64 := func(s string) string {
        return base64.StdEncoding.EncodeToString([]byte(s))
    }
    client.SandboxFiles(sandbox.ID).WriteMany(ctx, []miosa.WriteFileInput{
        {Path: "/workspace/index.html", ContentBase64: import64("<h1>Hello</h1>")},
    })

    // 7. Mint a preview token
    expiresIn := 3600
    token, _ := client.Sandboxes.PreviewToken(ctx, sandbox.ID, miosa.PreviewTokenInput{
        ExpiresIn: expiresIn,
        Scope:     "read",
    })
    fmt.Println("Preview URL:", token.URL)

    // 8. Create a public share link
    shareExpiresIn := 86400
    share, _ := client.SandboxShare(sandbox.ID).Create(ctx, miosa.CreateShareInput{
        ExpiresIn: &shareExpiresIn,
        Scope:     "read",
    })
    fmt.Println("Public URL:", share.ShareURL)

    // 9. Query usage
    report, _ := client.Usage.Get(ctx, miosa.UsageParams{
        ExternalUserID: "usr_dr_smith",
        Period:         "30d",
    })
    fmt.Println(report)

    // 10. Clean up
    client.Sandboxes.Delete(ctx, sandbox.ID)
}

Common patterns

Context-based timeouts

ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()

result, err := client.Exec.Run(ctx, computerID, miosa.ExecParams{
    Command: "npm run build",
    Timeout: 80,
})

Idempotency key

import "github.com/google/uuid"

sandbox, err := client.Sandboxes.Create(ctx, miosa.CreateSandboxInput{
    Name:           "my-sandbox",
    IdempotencyKey: uuid.NewString(),
})

Custom base URL (self-hosted)

client := miosa.NewClient(
    "msk_live_...",
    miosa.WithBaseURL("https://api.your-domain.com/api/v1"),
)

Resource coverage

Resource groupAvailable
Sandboxes (create, get, list, delete, update, previewToken, fork)
Sandbox files (tree, writeMany, watch)
Sandbox env, processes, share
Computers (CRUD + lifecycle)
Computer sub-resources (terminal, env, ports, volumes, logs, auto-stop, metrics)
Desktop
Files (upload, download, list, delete)
Exec
Deployments
Databases (managed Postgres)
Storage (object storage)
Volumes
Custom domains
Functions / cron jobs / health checks / webhooks
Sandbox templates
API keys
Tenant (plan, preview domain, branding)
Regions / settings
Dashboard / analytics / audit log / usage / quotas
Channels / integrations
External keys
MCP
Models / completions / embeddings
Command center / builder sessions / community
OpenComputers (hosts, jobs, files, tunnels, agents, clusters)
Workspace members + invites
Org invites
Admin
Snapshots (standalone)
Credits

Where to next

Was this helpful?