{"components":{"parameters":{"X-Signature":{"description":"HMAC-SHA256 signature as lowercase hex.\nComputed as: HMAC-SHA256(secret_key, \"{timestamp}:{METHOD}:{path}:{body}\")\n","example":"a1b2c3d4e5f6...","in":"header","name":"X-Signature","required":true,"schema":{"type":"string"}},"X-Timestamp":{"description":"Unix timestamp in seconds. Must be within +/-5 minutes of server time.","example":1704931200,"in":"header","name":"X-Timestamp","required":true,"schema":{"type":"integer"}}},"schemas":{"Artifact":{"properties":{"data":{"description":"Base64-encoded binary data","type":"string"},"filename":{"type":"string"},"type":{"enum":["base64"],"type":"string"}},"type":"object"},"AsyncJobResponse":{"properties":{"detected_language":{"description":"Only present for /run/async","type":"string"},"job_id":{"type":"string"},"message":{"type":"string"},"status":{"enum":["pending"],"type":"string"}},"type":"object"},"AuditLogEntry":{"properties":{"action":{"description":"Action performed (create, destroy, freeze, unfreeze, snapshot, etc.)","type":"string"},"client_ip":{"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"resource_id":{"type":"string"},"resource_type":{"description":"Type of resource (service, session, snapshot, image, contact)","type":"string"},"result":{"enum":["success","failure"],"type":"string"},"timestamp":{"format":"date-time","type":"string"}},"type":"object"},"CancelResponse":{"properties":{"artifacts":{"items":{"$ref":"#/components/schemas/Artifact"},"type":"array"},"completed_at":{"format":"date-time","type":"string"},"job_id":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"},"stdout":{"type":"string"},"success":{"type":"boolean"}},"type":"object"},"ClusterStatus":{"properties":{"allocated":{"type":"integer"},"available":{"type":"integer"},"mode":{"enum":["pooled","on_demand"],"type":"string"},"network_breakdown":{"properties":{"semitrusted":{"$ref":"#/components/schemas/NetworkPoolStats"},"zerotrust":{"$ref":"#/components/schemas/NetworkPoolStats"}},"type":"object"},"network_mode":{"enum":["zerotrust_only","semitrusted_only","hybrid"],"type":"string"},"pool_size":{"type":"integer"},"spawning":{"type":"integer"},"total_containers":{"type":"integer"}},"type":"object"},"Contact":{"properties":{"created_at":{"format":"date-time","type":"string"},"email":{"format":"email","type":"string"},"invited_by":{"format":"email","type":"string"},"role":{"enum":["owner","operator","reader"],"type":"string"},"verified":{"description":"Whether the contact has verified their email","type":"boolean"}},"type":"object"},"CreateServiceRequest":{"properties":{"bootstrap":{"description":"Bootstrap script content or URL","type":"string"},"bootstrap_content":{"description":"Bootstrap script content (alternative to bootstrap, auto-populated from bootstrap if not a URL)","type":"string"},"config":{"additionalProperties":true,"description":"Additional service configuration","type":"object"},"custom_domains":{"description":"Custom domain names","items":{"type":"string"},"type":"array"},"env":{"additionalProperties":{"type":"string"},"description":"Environment variables as key-value pairs (stored encrypted in vault)","type":"object"},"env_file":{"description":"Environment variables in .env format (KEY=value per line)","type":"string"},"golden_image":{"description":"Override base container image (for testing with different images)","type":"string"},"input_files":{"items":{"properties":{"content":{"description":"Base64-encoded content","type":"string"},"filename":{"type":"string"}},"type":"object"},"type":"array"},"name":{"description":"Service name (becomes NAME.on.unsandbox.com)","type":"string"},"network_mode":{"default":"semitrusted","enum":["zerotrust","semitrusted"],"type":"string"},"ports":{"description":"Ports to expose","items":{"type":"integer"},"type":"array"},"service_type":{"description":"SRV-enabled service type for tunnel allocation (minecraft, mumble, teamspeak, source, tcp, udp)","enum":["minecraft","mumble","teamspeak","source","tcp","udp"],"type":"string"},"unfreeze_on_demand":{"default":false,"description":"Auto-unfreeze on first HTTP request when frozen","type":"boolean"},"vcpu":{"default":1,"description":"Number of vCPUs (1-8). Each vCPU includes 2GB RAM.","maximum":8,"minimum":1,"type":"integer"}},"required":["name"],"type":"object"},"CreateSessionRequest":{"properties":{"network_mode":{"default":"zerotrust","enum":["zerotrust","semitrusted"],"type":"string"},"shell":{"default":"bash","description":"Shell or REPL to start (bash, python3, node, etc.)","type":"string"},"ttl":{"default":3600,"description":"Time-to-live in seconds (0 = no limit)","type":"integer"}},"type":"object"},"CreateSnapshotRequest":{"properties":{"hot":{"default":false,"type":"boolean"},"name":{"type":"string"},"source_id":{"type":"string"},"source_type":{"enum":["session","service"],"type":"string"},"ttl":{"type":"integer"}},"required":["source_type","source_id"],"type":"object"},"ErrorResponse":{"properties":{"details":{"type":"string"},"error":{"type":"string"},"success":{"type":"boolean"}},"required":["error"],"type":"object"},"ExecuteRequest":{"properties":{"code":{"description":"Source code to execute","example":"print(42)","type":"string"},"env":{"additionalProperties":{"type":"string"},"description":"Environment variables as key-value pairs","example":{"API_KEY":"secret","DEBUG":"true"},"type":"object"},"input_files":{"description":"Files to place in /tmp/ before execution","items":{"properties":{"content":{"description":"Base64-encoded file content","type":"string"},"filename":{"description":"Filename (placed in /tmp/)","type":"string"}},"required":["filename","content"],"type":"object"},"type":"array"},"language":{"description":"Programming language identifier. Use GET /languages for the full list.","example":"python","type":"string"},"network_mode":{"default":"zerotrust","description":"Network isolation mode:\n- zerotrust: No network access (default, most secure)\n- semitrusted: Internet access via proxy\n","enum":["zerotrust","semitrusted"],"type":"string"},"return_artifact":{"default":false,"description":"Return compiled native binary as base64 (for compiled languages)","type":"boolean"},"return_wasm_artifact":{"default":false,"description":"Return WebAssembly binary as base64 (for WASM-compatible languages)","type":"boolean"},"ttl":{"default":60,"description":"Time-to-live in seconds (1-900, default 60)","maximum":900,"minimum":1,"type":"integer"},"vcpu":{"default":1,"description":"Number of vCPUs (1-8). Each vCPU includes 2GB RAM.","maximum":8,"minimum":1,"type":"integer"}},"required":["language","code"],"type":"object"},"ExecuteResponse":{"properties":{"artifact":{"$ref":"#/components/schemas/Artifact"},"exit_code":{"type":"integer"},"job_id":{"type":"string"},"language":{"type":"string"},"network_mode":{"enum":["zerotrust","semitrusted"],"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"},"success":{"type":"boolean"},"total_time_ms":{"type":"integer"},"wasm_artifact":{"$ref":"#/components/schemas/Artifact"}},"type":"object"},"ImageResponse":{"properties":{"created_at":{"format":"date-time","type":"string"},"description":{"type":"string"},"fingerprint":{"description":"LXD image fingerprint","type":"string"},"id":{"description":"Image ID (unsb-image-xxxx-xxxx-xxxx-xxxx)","type":"string"},"locked":{"type":"boolean"},"name":{"type":"string"},"node":{"description":"LXD host where image is stored","type":"string"},"owner_api_key":{"type":"string"},"size_bytes":{"type":"integer"},"source_id":{"type":"string"},"source_type":{"enum":["service","snapshot"],"type":"string"},"trusted_keys":{"description":"API keys with granted access","items":{"type":"string"},"type":"array"},"visibility":{"enum":["private","unlisted","public"],"type":"string"}},"type":"object"},"ImageSummary":{"properties":{"created_at":{"format":"date-time","type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"locked":{"type":"boolean"},"name":{"type":"string"},"size_bytes":{"type":"integer"},"visibility":{"enum":["private","unlisted","public"],"type":"string"}},"type":"object"},"JobStatus":{"properties":{"artifacts":{"items":{"$ref":"#/components/schemas/Artifact"},"type":"array"},"completed_at":{"format":"date-time","type":"string"},"created_at":{"format":"date-time","type":"string"},"error":{"type":"string"},"exit_code":{"type":"integer"},"job_id":{"type":"string"},"language":{"type":"string"},"network_mode":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"enum":["pending","running","completed","cancelled","timeout","failed"],"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"},"success":{"type":"boolean"},"timeout":{"type":"integer"},"total_time_ms":{"type":"integer"}},"type":"object"},"JobSummary":{"properties":{"created_at":{"format":"date-time","type":"string"},"job_id":{"type":"string"},"language":{"type":"string"},"network_mode":{"type":"string"},"status":{"enum":["pending","running","completed","cancelled","timeout","failed"],"type":"string"}},"type":"object"},"LanguagesResponse":{"properties":{"aliases":{"additionalProperties":{"type":"string"},"type":"object"},"count":{"type":"integer"},"languages":{"items":{"type":"string"},"type":"array"}},"type":"object"},"NetworkPoolStats":{"properties":{"allocated":{"description":"Pool containers + active services combined","type":"integer"},"available":{"type":"integer"},"pool_allocated":{"description":"Just ephemeral pool containers (excludes services)","type":"integer"},"services":{"description":"Active services in this network mode","type":"integer"},"total":{"type":"integer"}},"type":"object"},"PublishImageRequest":{"properties":{"description":{"description":"Optional description","type":"string"},"name":{"description":"User-friendly name for the image","type":"string"},"source_id":{"description":"ID of the service or snapshot to publish","type":"string"},"source_type":{"description":"Type of source to publish from","enum":["service","snapshot"],"type":"string"}},"required":["source_type","source_id"],"type":"object"},"RunResponse":{"properties":{"detected_language":{"type":"string"},"exit_code":{"type":"integer"},"job_id":{"type":"string"},"language":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"},"success":{"type":"boolean"}},"type":"object"},"ServiceResponse":{"properties":{"created_at":{"format":"date-time","type":"string"},"disk_size":{"description":"Data size in bytes (logical referenced)","type":"integer"},"disk_used":{"description":"Disk cost in bytes (actual ZFS usage)","type":"integer"},"locked":{"description":"Whether the service is locked against deletion","type":"boolean"},"name":{"type":"string"},"ports":{"items":{"type":"integer"},"type":"array"},"service_id":{"type":"string"},"state":{"enum":["starting","running","frozen","sleeping","waking","redeploying","failed"],"type":"string"},"unfreeze_on_demand":{"description":"Auto-unfreeze on HTTP request when frozen","type":"boolean"},"url":{"type":"string"},"vcpu":{"description":"Current vCPU allocation","type":"integer"},"websocket_url":{"description":"WebSocket shell URL (e.g., /sessions/{service_id}/shell)","type":"string"}},"type":"object"},"ServiceSummary":{"properties":{"domains":{"items":{"type":"string"},"type":"array"},"locked":{"type":"boolean"},"name":{"type":"string"},"ports":{"items":{"type":"integer"},"type":"array"},"service_id":{"type":"string"},"state":{"type":"string"}},"type":"object"},"SessionResponse":{"properties":{"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"network_mode":{"type":"string"},"session_id":{"type":"string"},"shell":{"type":"string"},"status":{"enum":["running","frozen","terminated"],"type":"string"},"websocket_url":{"type":"string"}},"type":"object"},"SessionSummary":{"properties":{"network_mode":{"type":"string"},"remaining_ttl":{"type":"integer"},"session_id":{"type":"string"},"status":{"type":"string"}},"type":"object"},"ShellsResponse":{"properties":{"categories":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Shells grouped by category","type":"object"},"count":{"description":"Total number of supported shells","type":"integer"},"shells":{"description":"Sorted list of all supported shell names","items":{"type":"string"},"type":"array"}},"type":"object"},"SnapshotRequest":{"properties":{"hot":{"default":false,"description":"Create hot snapshot (without stopping container)","type":"boolean"},"name":{"description":"Optional snapshot name","type":"string"},"ttl":{"description":"Auto-delete after N seconds (optional)","type":"integer"}},"type":"object"},"SnapshotResponse":{"properties":{"created_at":{"format":"date-time","type":"string"},"disk_bytes":{"description":"Actual disk cost in bytes (ZFS usage)","type":"integer"},"name":{"type":"string"},"size_bytes":{"description":"Logical data size in bytes","type":"integer"},"snapshot_id":{"type":"string"},"source_id":{"type":"string"},"source_type":{"type":"string"}},"type":"object"},"SnapshotSummary":{"properties":{"id":{"type":"string"},"locked":{"type":"boolean"},"name":{"type":"string"},"size_bytes":{"type":"integer"},"source_id":{"type":"string"},"source_type":{"type":"string"}},"type":"object"}},"securitySchemes":{"bearerAuth":{"description":"Enter your **public key** (unsb-pk-xxxx-xxxx-xxxx-xxxx).\n\n**Note**: Full authentication also requires X-Timestamp and X-Signature headers.\nSwagger UI can only set the Authorization header. For testing:\n1. Use the Swagger UI with just your public key (works for read-only endpoints)\n2. For full HMAC auth, use curl or a client library that computes signatures\n\nGet your keys at: https://unsandbox.com/pricing-for-agents\n","scheme":"bearer","type":"http"}}},"info":{"contact":{"name":"Unsandbox Support","url":"https://unsandbox.com"},"description":"Secure code execution service supporting 42+ programming languages in isolated containers.\n\n## Features\n- Synchronous and asynchronous execution modes\n- Automatic language detection from code\n- Binary artifact extraction for compiled languages\n- WebAssembly compilation for supported languages\n- Network isolation modes (zerotrust/semitrusted)\n- Interactive shell sessions with WebSocket access\n- Persistent services with custom domains\n- Snapshots for state preservation\n- API key management with RBAC contacts\n- Audit logging for all major operations\n- Live token minting and revocation\n- Custom domain management for services\n- Environment variable vault (encrypted)\n- Service resize (vCPU/memory) and upgrade tracking\n- Auto-unfreeze on demand for sleeping services\n\n## Authentication\nAll endpoints require API key authentication via HMAC signatures.\n\n**API Keys**: Get your keys at https://unsandbox.com/pricing-for-agents\n- **Public key** (`unsb-pk-xxxx-xxxx-xxxx-xxxx`): Identifies your account, sent in requests\n- **Secret key** (`unsb-sk-xxxxx-xxxxx-xxxxx-xxxxx`): Used locally to compute signatures, **never transmitted**\n\n**Required Headers**:\n- `Authorization: Bearer <public_key>`\n- `X-Timestamp: <unix_timestamp>` (must be within +/-5 minutes of server time)\n- `X-Signature: <hmac_hex>`\n\n**Signature Computation**:\n```\nmessage = \"{timestamp}:{METHOD}:{path}:{body}\"\nsignature = HMAC-SHA256(secret_key, message).hex().lowercase()\n```\n- `timestamp`: Unix timestamp (same as X-Timestamp header)\n- `METHOD`: HTTP method in uppercase (GET, POST, DELETE, etc.)\n- `path`: Request path including query string (e.g., `/execute` or `/run?ttl=120`)\n- `body`: Raw request body (empty string for GET/DELETE)\n\n**Environment Variables** (recommended):\n```\nexport UNSANDBOX_PUBLIC_KEY=unsb-pk-xxxx-xxxx-xxxx-xxxx\nexport UNSANDBOX_SECRET_KEY=unsb-sk-xxxxx-xxxxx-xxxxx-xxxxx\n```\n\nSee https://unsandbox.com/docs for language-specific examples.\n","title":"Unsandbox Code Execution API","version":"2.2.0"},"openapi":"3.0.3","paths":{"/services/{id}/port":{"get":{"description":"Check if a specific port is listening inside the service container.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Port number to check (1-65535)","in":"query","name":"port","required":true,"schema":{"maximum":65535,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"listening":true,"port":8080,"service_id":"svc-abc123"}}},"description":"Port status"},"400":{"description":"Missing or invalid port parameter"},"404":{"description":"Service not found"}},"summary":"Check service port status","tags":["Services"]}},"/pools":{"get":{"description":"Get status of all registered container pools (horizontal scaling).","responses":{"200":{"content":{"application/json":{"example":{"pool_count":2,"pools":[{"allocated":4,"available":140,"id":"pool_manager@cammy","total":144},{"allocated":4,"available":140,"id":"pool_manager@ai","total":144}],"total_allocated":8,"total_available":280,"total_capacity":288}}},"description":"Pool list"}},"summary":"List all pools","tags":["System"]}},"/images/{id}/revoke":{"post":{"description":"Revoke previously granted access from an API key.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"api_key":"unsb-pk-xxxx-xxxx-xxxx-xxxx"},"schema":{"properties":{"api_key":{"description":"API key to revoke access from","type":"string"}},"required":["api_key"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Access revoked"}},"summary":"Revoke image access","tags":["Images"]}},"/keys/self/audit-log":{"get":{"description":"Retrieve audit log entries for the authenticated API key.\nLogs all major operations: create, destroy, freeze, unfreeze, snapshot, etc.\n","responses":{"200":{"content":{"application/json":{"example":{"count":2,"entries":[{"action":"create","client_ip":"203.0.113.1","metadata":{"name":"myapp","network_mode":"semitrusted","vcpu":1},"resource_id":"svc-abc123","resource_type":"service","result":"success","timestamp":"2026-01-20T14:00:00Z"},{"action":"destroy","client_ip":"203.0.113.1","resource_id":"svc-abc123","resource_type":"service","result":"success","timestamp":"2026-01-21T09:30:00Z"}]},"schema":{"properties":{"count":{"type":"integer"},"entries":{"items":{"$ref":"#/components/schemas/AuditLogEntry"},"type":"array"}},"type":"object"}}},"description":"Audit log entries"},"503":{"description":"Portal unavailable"}},"summary":"Get audit log","tags":["API Keys"]}},"/stats":{"get":{"description":"Get detailed system statistics including load and container metrics.","responses":{"200":{"content":{"application/json":{"example":{"containers":285,"load_15min":"1.45","load_1min":"2.15","load_5min":"1.89"}}},"description":"System stats"}},"summary":"System statistics","tags":["System"]}},"/keys/self/contacts/{email}":{"delete":{"description":"Remove a contact from the API key. Only owners can manage contacts.","parameters":[{"in":"path","name":"email","required":true,"schema":{"format":"email","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"success":true}}},"description":"Contact removed"},"403":{"description":"Only owners can manage contacts"},"404":{"description":"Contact not found"},"422":{"content":{"application/json":{"example":{"error":"Cannot remove the last owner"}}},"description":"Cannot remove the last owner"}},"summary":"Remove contact","tags":["API Keys"]},"patch":{"description":"Change a contact's role. Only owners can manage contacts.","parameters":[{"in":"path","name":"email","required":true,"schema":{"format":"email","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"role":"owner"},"schema":{"properties":{"role":{"enum":["owner","operator","reader"],"type":"string"}},"required":["role"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"contact":{"email":"dev@example.com","role":"owner"},"success":true}}},"description":"Contact updated"},"403":{"description":"Only owners can manage contacts"},"404":{"description":"Contact not found"},"422":{"content":{"application/json":{"example":{"error":"Cannot demote the last owner"}}},"description":"Cannot demote the last owner"}},"summary":"Update contact role","tags":["API Keys"]}},"/services/{id}/redeploy":{"post":{"description":"Re-run the bootstrap script. Optionally provide new bootstrap content.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"bootstrap_content":{"description":"New bootstrap script (optional)","type":"string"}},"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"example":{"service_id":"svc-abc123","state":"redeploying"}}},"description":"Redeployment started"}},"summary":"Redeploy service","tags":["Services"]}},"/sessions/{id}/extend":{"post":{"description":"Add additional time to a session's time-to-live.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"seconds":7200},"schema":{"properties":{"seconds":{"default":3600,"description":"Seconds to add (default 3600)","type":"integer"}},"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"example":{"ttl":10800}}},"description":"TTL extended"},"404":{"description":"Session not found"}},"summary":"Extend session TTL","tags":["Sessions"]}},"/snapshots/{id}/unlock":{"post":{"description":"Unlock a locked snapshot to allow deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"locked":false}}},"description":"Snapshot unlocked"}},"summary":"Unlock snapshot","tags":["Snapshots"]}},"/images/{id}/spawn":{"post":{"description":"Create a new service using this image as the base.\nThe image fingerprint is used as the golden_image for the service container.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"my-app-instance","network_mode":"semitrusted","ports":[8080]},"schema":{"properties":{"bootstrap":{"description":"Optional bootstrap script (image may already have app)","type":"string"},"name":{"description":"Service name","type":"string"},"network_mode":{"default":"zerotrust","enum":["zerotrust","semitrusted"],"type":"string"},"ports":{"description":"Ports to expose","items":{"type":"integer"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"name":"my-app-instance","service_id":"unsb-service-xyz789","source_image":"unsb-image-abc123","state":"starting"}}},"description":"Service created from image"},"429":{"description":"Concurrency limit reached"}},"summary":"Spawn service from image","tags":["Images"]}},"/snapshots/{id}/restore":{"post":{"description":"Restore a snapshot to its original source (session or service).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"snapshot_id":"snap-abc123","status":"restored"}}},"description":"Snapshot restored"}},"summary":"Restore snapshot","tags":["Snapshots"]}},"/snapshots":{"get":{"description":"Returns all snapshots for the authenticated API key.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"snapshots":{"items":{"$ref":"#/components/schemas/SnapshotSummary"},"type":"array"}},"type":"object"}}},"description":"List of snapshots"}},"summary":"List snapshots","tags":["Snapshots"]},"post":{"description":"Create a snapshot from an existing session or service.","requestBody":{"content":{"application/json":{"example":{"name":"before-upgrade","source_id":"svc-abc123","source_type":"service"},"schema":{"$ref":"#/components/schemas/CreateSnapshotRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotResponse"}}},"description":"Snapshot created"}},"summary":"Create snapshot","tags":["Snapshots"]}},"/services/{id}/unlock":{"post":{"description":"Unlock a locked service to allow deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"locked":false}}},"description":"Service unlocked"}},"summary":"Unlock service","tags":["Services"]}},"/cluster":{"get":{"description":"Get information about the container pool and system status.","responses":{"200":{"content":{"application/json":{"example":{"allocated":5,"available":280,"mode":"pooled","network_breakdown":{"semitrusted":{"allocated":3,"available":140,"services":1,"total":143},"zerotrust":{"allocated":2,"available":140,"total":142}},"network_mode":"hybrid","pool_size":288,"spawning":0,"total_containers":285},"schema":{"$ref":"#/components/schemas/ClusterStatus"}}},"description":"Cluster status"}},"summary":"Get cluster status","tags":["System"]}},"/images/{id}/clone":{"post":{"description":"Create a copy of an image that you own.\nUse this to make your own copy of a public or shared image.\nThe cloned image will be owned by you with private visibility.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"description":"My personal copy","name":"my-copy-of-app"},"schema":{"properties":{"description":{"description":"Description for the cloned image","type":"string"},"name":{"description":"Name for the cloned image (defaults to original name + \" (copy)\")","type":"string"}},"type":"object"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Image cloned successfully"},"403":{"description":"Not authorized to clone this image (private image you don't have access to)"},"429":{"description":"Image storage limit exceeded"}},"summary":"Clone image","tags":["Images"]}},"/keys/self":{"get":{"description":"Retrieve metadata for the authenticated API key including email, tier, and contacts count.","responses":{"200":{"content":{"application/json":{"example":{"contacts_count":2,"created_at":"2025-06-15T10:30:00Z","email":"user@example.com","key":"unsb-pk-xxxx-xxxx-xxxx-xxxx","sudo_required":true,"tier":3},"schema":{"properties":{"contacts_count":{"description":"Number of contacts associated with this key","type":"integer"},"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"key":{"description":"Public key identifier","type":"string"},"sudo_required":{"description":"Whether destructive operations require OTP verification","type":"boolean"},"tier":{"description":"Subscription tier (0=free, 1-4=paid)","type":"integer"}},"type":"object"}}},"description":"Key info"},"404":{"description":"API key not found"},"503":{"description":"Portal unavailable"}},"summary":"Get current API key info","tags":["API Keys"]},"patch":{"description":"Update email or sudo settings for the authenticated API key.","requestBody":{"content":{"application/json":{"examples":{"enable_sudo":{"summary":"Enable sudo OTP","value":{"sudo_required":true}},"update_email":{"summary":"Update email","value":{"email":"newemail@example.com"}}},"schema":{"properties":{"email":{"description":"New email address","type":"string"},"sudo_required":{"description":"Require OTP for destructive operations","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"key":{"email":"newemail@example.com","key":"unsb-pk-xxxx-xxxx-xxxx-xxxx","sudo_required":true},"success":true}}},"description":"Settings updated"},"400":{"content":{"application/json":{"example":{"error":"No valid fields to update. Accepted: email, sudo_required"}}},"description":"No valid fields to update"},"404":{"description":"API key not found"}},"summary":"Update API key settings","tags":["API Keys"]}},"/pools/{id}/stats":{"get":{"description":"Get detailed stats for a specific pool by ID (e.g., `ai`, `cammy`).","parameters":[{"description":"Pool identifier (e.g., ai, cammy)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"allocated":2,"available":140,"load_avg":{"load1":"2.15","load15":"1.45","load5":"1.89"},"memory":{"available_mb":32768,"total_mb":65536,"used_mb":32768,"used_percent":50.0},"mode":"pooled","network_breakdown":{"semitrusted":{"allocated":1,"available":70,"pool_allocated":0,"services":1,"total":71},"zerotrust":{"allocated":1,"available":70,"pool_allocated":1,"services":0,"total":71}},"network_mode":"hybrid","pool_size":144,"spawning":0,"total_containers":142}}},"description":"Pool stats"},"404":{"description":"Pool not found"}},"summary":"Get specific pool stats","tags":["System"]}},"/services/{id}/restore":{"post":{"description":"Restore a service to a previous snapshot state.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"snapshot_id":{"type":"string"}},"required":["snapshot_id"],"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"example":{"service_id":"svc-abc123","status":"restored"}}},"description":"Service restored"},"404":{"description":"Service or snapshot not found"}},"summary":"Restore service from snapshot","tags":["Services"]}},"/version":{"get":{"description":"Returns API version, git commit hash, build time, and service identifier.\nUseful for verifying deployments succeeded.\n","responses":{"200":{"content":{"application/json":{"example":{"build_time":"2026-02-06T22:00:00Z","git_commit":"64e22b9","service":"api","version":"2.2.0"},"schema":{"properties":{"build_time":{"format":"date-time","type":"string"},"git_commit":{"type":"string"},"service":{"type":"string"},"version":{"type":"string"}},"type":"object"}}},"description":"Version info"}},"summary":"API version","tags":["System"]}},"/run/async":{"post":{"description":"Submit raw code, auto-detect language, and execute asynchronously.\nReturns job ID immediately for polling.\n","parameters":[{"in":"query","name":"ttl","schema":{"default":60,"maximum":900,"minimum":1,"type":"integer"}},{"in":"query","name":"network_mode","schema":{"default":"zerotrust","enum":["zerotrust","semitrusted"],"type":"string"}}],"requestBody":{"content":{"text/plain":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"detected_language":"python","job_id":"ba943906-4ea6-a61c-9980-445f459368d","message":"Job accepted for execution","status":"pending"},"schema":{"$ref":"#/components/schemas/AsyncJobResponse"}}},"description":"Job accepted"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Detection failed"}},"summary":"Auto-detect language and execute asynchronously","tags":["Execution"]}},"/services/{id}":{"delete":{"description":"Permanently destroy a service and its container.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"service_id":"svc-abc123","status":"destroyed"}}},"description":"Service destroyed"},"400":{"description":"Service is locked"},"404":{"description":"Service not found"}},"summary":"Destroy service","tags":["Services"]},"get":{"description":"Get detailed service information including state, ports, and health.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResponse"}}},"description":"Service details"},"404":{"description":"Service not found"}},"summary":"Get service status","tags":["Services"]},"patch":{"description":"Update service configuration. Supports:\n- **vcpu**: Live resize of vCPU and memory (each vCPU = 2GB RAM)\n- **unfreeze_on_demand**: Auto-unfreeze on first HTTP request when frozen\n- **show_freeze_page**: Show a branded freeze page instead of 502 when frozen\n\nOnly one setting can be updated per request.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"auto_unfreeze":{"summary":"Enable auto-unfreeze","value":{"unfreeze_on_demand":true}},"freeze_page":{"summary":"Enable freeze page","value":{"show_freeze_page":true}},"resize":{"summary":"Resize to 4 vCPU","value":{"vcpu":4}}},"schema":{"properties":{"show_freeze_page":{"description":"Show branded freeze page instead of 502","type":"boolean"},"unfreeze_on_demand":{"description":"Auto-unfreeze on HTTP request when frozen","type":"boolean"},"vcpu":{"description":"Target vCPU count (1-8, each gets 2GB RAM)","maximum":8,"minimum":1,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"service_id":"svc-abc123","success":true,"vcpu":4}}},"description":"Service updated"},"400":{"content":{"application/json":{"example":{"error":"Must provide vcpu, unfreeze_on_demand, or show_freeze_page parameter"}}},"description":"Invalid parameter"},"403":{"description":"Not authorized"},"404":{"description":"Service not found"},"429":{"content":{"application/json":{"example":{"current_usage":3,"error":"concurrency_limit_exceeded","limit":5,"message":"Cannot resize: would exceed tier concurrency limit","projected_usage":10,"requested_vcpu":8}}},"description":"Concurrency limit exceeded (resize would exceed tier limit)"}},"summary":"Update service settings","tags":["Services"]}},"/sessions/{id}/snapshot":{"post":{"description":"Create a snapshot of the session's container state.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotResponse"}}},"description":"Snapshot created"}},"summary":"Create session snapshot","tags":["Sessions"]}},"/sessions/{id}/unlock":{"post":{"description":"Unlock a locked session to allow deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"locked":false,"session_id":"unsb-vm-abc123"}}},"description":"Session unlocked"}},"summary":"Unlock session","tags":["Sessions"]}},"/images/{id}/unlock":{"post":{"description":"Unlock a locked image to allow deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Image unlocked"}},"summary":"Unlock image","tags":["Images"]}},"/services/{id}/upgrade/progress":{"get":{"description":"Returns current upgrade state, progress percentage, and version chain for a service undergoing OS upgrade.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"not_upgrading":{"summary":"No upgrade running","value":{"upgrading":false}},"upgrading":{"summary":"Upgrade in progress","value":{"current_version":"22.04","progress":45,"state":"running","target_version":"24.04","upgrading":true}}}}},"description":"Upgrade progress"},"404":{"description":"Service not found"}},"summary":"Get OS upgrade progress","tags":["Services"]}},"/snapshots/{id}/lock":{"post":{"description":"Lock snapshot to prevent accidental deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"locked":true}}},"description":"Snapshot locked"}},"summary":"Lock snapshot","tags":["Snapshots"]}},"/services/{id}/domains":{"put":{"description":"Manage custom domain names for a service. Supports three request formats:\n- `custom_domains`: Replace entire domain list\n- `add`: Append domains to existing list\n- `remove`: Remove specific domains from list\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"add":{"summary":"Add domains","value":{"add":["staging.example.com"]}},"remove":{"summary":"Remove domains","value":{"remove":["old.example.com"]}},"replace":{"summary":"Replace all domains","value":{"custom_domains":["myapp.example.com","www.example.com"]}}},"schema":{"properties":{"add":{"description":"Add these domains to existing list","items":{"type":"string"},"type":"array"},"custom_domains":{"description":"Replace all domains with this list","items":{"type":"string"},"type":"array"},"remove":{"description":"Remove these domains from existing list","items":{"type":"string"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"custom_domains":["myapp.example.com","www.example.com"],"service_id":"svc-abc123","success":true}}},"description":"Domains updated"},"400":{"content":{"application/json":{"example":{"error":"Invalid request","message":"Expected JSON with one of: {\"custom_domains\": [...]}, {\"add\": [...]}, or {\"remove\": [...]}"}}},"description":"Invalid request format"},"403":{"description":"Not authorized"},"404":{"description":"Service not found"}},"summary":"Update service custom domains","tags":["Services"]}},"/services":{"get":{"description":"Returns all services for the authenticated API key.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"services":{"items":{"$ref":"#/components/schemas/ServiceSummary"},"type":"array"}},"type":"object"}}},"description":"List of services"}},"summary":"List services","tags":["Services"]},"post":{"description":"Create a long-running service with custom subdomain.\nServices persist until explicitly destroyed and can auto-unfreeze on HTTP requests.\n","requestBody":{"content":{"application/json":{"examples":{"web_server":{"summary":"Simple web server","value":{"bootstrap":"#!/bin/bash\napt-get update && apt-get install -y nginx\nsystemctl enable nginx\nsystemctl start nginx\n","name":"myapp","ports":[80]}},"with_files":{"summary":"With input files","value":{"bootstrap":"#!/bin/bash\ncd /tmp && tar xzf app.tar.gz\n./start.sh\n","input_files":[{"content":"H4sIAAAAAAAAA...","filename":"app.tar.gz"}],"name":"api","ports":[8080]}}},"schema":{"$ref":"#/components/schemas/CreateServiceRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"created_at":"2025-01-11T12:00:00Z","name":"myapp","ports":[80],"service_id":"svc-abc123","state":"starting","url":"https://myapp.on.unsandbox.com"},"schema":{"$ref":"#/components/schemas/ServiceResponse"}}},"description":"Service created"}},"summary":"Create service","tags":["Services"]}},"/images/{id}":{"delete":{"description":"Permanently delete an image from LXD and the database.\nCannot delete locked images.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"message":"Image deleted","success":true}}},"description":"Image deleted"},"404":{"description":"Image not found"},"409":{"description":"Image is locked"}},"summary":"Delete image","tags":["Images"]},"get":{"description":"Get detailed information about an image.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Image details"},"404":{"description":"Image not found"}},"summary":"Get image details","tags":["Images"]}},"/images/{id}/trusted":{"get":{"description":"List all API keys that have been granted access to this image.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"trusted_keys":["unsb-pk-aaaa-bbbb-cccc-dddd","unsb-pk-1111-2222-3333-4444"]},"schema":{"properties":{"trusted_keys":{"items":{"type":"string"},"type":"array"}},"type":"object"}}},"description":"List of trusted API keys"}},"summary":"List trusted API keys","tags":["Images"]}},"/mint-token":{"post":{"description":"Create a short-lived token for client-side use (e.g., browser WebSocket connections).\nTokens inherit the parent key's permissions but expire quickly.\n","requestBody":{"content":{"application/json":{"example":{},"schema":{"properties":{"ttl":{"description":"Token TTL in seconds","type":"integer"}},"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"example":{"expires_at":"2026-01-20T14:30:00Z","token":"unsb-lt-xxxxxxxx"}}},"description":"Token minted"},"400":{"description":"Token minting failed"},"401":{"description":"Missing API key"}},"summary":"Mint a live token","tags":["API Keys"]}},"/services/{id}/freeze":{"post":{"description":"Freeze a service to save resources. Auto-unfreezes on first HTTP request to the service URL.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"service_id":"svc-abc123","state":"frozen"}}},"description":"Service frozen"}},"summary":"Sleep service","tags":["Services"]}},"/execute/async":{"post":{"description":"Submit code for execution and receive a job ID immediately. Use `GET /jobs/{job_id}` to poll for results.\n","requestBody":{"content":{"application/json":{"examples":{"rust_compile":{"summary":"Rust compilation (may take time)","value":{"code":"fn main() {\n    println!(\"Hello from Rust!\");\n}\n","language":"rust","return_artifact":true,"ttl":120}}},"schema":{"$ref":"#/components/schemas/ExecuteRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"job_id":"ba943906-4ea6-a61c-9980-445f459368d","message":"Job accepted for execution","status":"pending"},"schema":{"$ref":"#/components/schemas/AsyncJobResponse"}}},"description":"Job accepted for execution"}},"summary":"Execute code asynchronously","tags":["Execution"]}},"/languages":{"get":{"description":"Returns all supported programming languages and their aliases.","responses":{"200":{"content":{"application/json":{"example":{"aliases":{"js":"javascript","lisp":"commonlisp","node":"javascript","ts":"typescript"},"count":42,"languages":["python","javascript","typescript","ruby","go","rust","c","cpp"]},"schema":{"$ref":"#/components/schemas/LanguagesResponse"}}},"description":"Language list"}},"summary":"List supported languages","tags":["Languages"]}},"/snapshots/{id}/clone":{"post":{"description":"Create a new session or service from a snapshot.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"to_service":{"value":{"name":"myapp-v2","type":"service"}},"to_session":{"value":{"shell":"bash","type":"session"}}},"schema":{"properties":{"name":{"description":"Service name (required for service type)","type":"string"},"shell":{"description":"Shell to use (for session type)","type":"string"},"type":{"enum":["session","service"],"type":"string"}},"required":["type"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"examples":{"service":{"value":{"name":"myapp-v2","service_id":"svc-xyz789","state":"starting"}},"session":{"value":{"session_id":"unsb-vm-xyz789","status":"running"}}}}},"description":"Clone created"}},"summary":"Clone snapshot","tags":["Snapshots"]}},"/run":{"post":{"description":"Submit raw code (text/plain) and automatically detect the programming language.\nUses shebang lines, syntax patterns, and heuristics for detection.\n","parameters":[{"description":"Time-to-live in seconds (1-900, default 60)","in":"query","name":"ttl","schema":{"default":60,"maximum":900,"minimum":1,"type":"integer"}},{"description":"Network isolation mode","in":"query","name":"network_mode","schema":{"default":"zerotrust","enum":["zerotrust","semitrusted"],"type":"string"}},{"description":"URL-encoded JSON object of environment variables","example":"%7B%22DEBUG%22%3A%221%22%7D","in":"query","name":"env","schema":{"type":"string"}}],"requestBody":{"content":{"text/plain":{"examples":{"commonlisp":{"summary":"Common Lisp - Fibonacci","value":"(loop for a = 0 then b and b = 1 then (+ a b) while (< a 1000) do (format t \"~a \" a))"},"java":{"summary":"Java - Fibonacci","value":"public class Main { public static void main(String[] args) { int a=0, b=1; while (a<1000) { System.out.print(a + \" \"); int tmp=a; a=b; b=tmp+b; } } }\n"},"ocaml":{"summary":"OCaml - Fibonacci","value":"let rec fib a b = if a < 1000 then (print_int a; print_char ' '; fib b (a+b)) in fib 0 1"},"zig":{"summary":"Zig - Fibonacci","value":"const std = @import(\"std\");\npub fn main() !void {\n    var a: u32 = 0; var b: u32 = 1;\n    while (a < 1000) { std.debug.print(\"{} \", .{a}); const tmp = a; a = b; b = tmp + b; }\n}\n"},"crystal":{"summary":"Crystal - Fibonacci","value":"a, b = 0, 1; while a < 1000; print a, ' '; a, b = b, a+b; end"},"julia":{"summary":"Julia - Fibonacci","value":"a, b = 0, 1; while a < 1000; print(a, \" \"); a, b = b, a+b; end"},"v":{"summary":"V - Fibonacci","value":"fn main() { mut a, mut b := 0, 1; for a < 1000 { print('${a} '); a, b = b, a+b } }\n"},"odin":{"summary":"Odin - Fibonacci","value":"package main\nimport \"core:fmt\"\nmain :: proc() { a, b := 0, 1; for a < 1000 { fmt.printf(\"%d \", a); a, b = b, a+b } }\n"},"ruby":{"summary":"Ruby - Fibonacci","value":"a, b = 0, 1; while a < 1000; print a, \" \"; a, b = b, a+b; end"},"c":{"summary":"C - Fibonacci","value":"#include <stdio.h>\nint main() { int a=0, b=1; while (a<1000) { printf(\"%d \", a); int tmp=a; a=b; b=tmp+b; } return 0; }\n"},"kotlin":{"summary":"Kotlin - Fibonacci","value":"fun main() { var a=0; var b=1; while (a<1000) { print(\"$a \"); val tmp=a; a=b; b=tmp+b } }"},"pascal":{"summary":"Pascal - Fibonacci","value":"program Fib;\nvar a, b, tmp: integer;\nbegin\n  a := 0; b := 1;\n  while a < 1000 do begin\n    write(a, ' '); tmp := a; a := b; b := tmp + b\n  end\nend.\n"},"tcl":{"summary":"Tcl - Fibonacci","value":"set a 0; set b 1; while {$a < 1000} { puts -nonewline \"$a \"; set tmp $a; set a $b; set b [expr {$tmp + $b}] }"},"powershell":{"summary":"PowerShell - Fibonacci","value":"$a=0; $b=1; while ($a -lt 1000) { Write-Host -NoNewline \"$a \"; $tmp=$a; $a=$b; $b=$tmp+$b }"},"lua":{"summary":"Lua - Fibonacci","value":"a, b = 0, 1; while a < 1000 do io.write(a, \" \"); a, b = b, a+b end"},"groovy":{"summary":"Groovy - Fibonacci","value":"def (a, b) = [0, 1]; while (a < 1000) { print \"$a \"; (a, b) = [b, a+b] }"},"perl":{"summary":"Perl - Fibonacci","value":"my ($a, $b) = (0, 1); while ($a < 1000) { print \"$a \"; ($a, $b) = ($b, $a+$b); }"},"r":{"summary":"R - Fibonacci","value":"a <- 0; b <- 1; while (a < 1000) { cat(a, \" \"); tmp <- a; a <- b; b <- tmp + b }"},"deno":{"summary":"Deno - Fibonacci","value":"let [a, b] = [0, 1]; while (a < 1000) { Deno.stdout.writeSync(new TextEncoder().encode(a + ' ')); [a, b] = [b, a+b]; }"},"nim":{"summary":"Nim - Fibonacci","value":"var a, b = 0, 1; while a < 1000: stdout.write $a & \" \"; swap a, b; b += a"},"csharp":{"summary":"C# - Fibonacci","value":"using System; class Program { static void Main() { int a=0, b=1; while (a<1000) { Console.Write(a + \" \"); int tmp=a; a=b; b=tmp+b; } } }"},"scheme":{"summary":"Scheme - Fibonacci","value":"(let loop ((a 0) (b 1)) (when (< a 1000) (display a) (display \" \") (loop b (+ a b))))"},"erlang":{"summary":"Erlang - Fibonacci","value":"F = fun G(A, B) -> case A < 1000 of true -> io:format(\"~p \", [A]), G(B, A+B); false -> ok end end, F(0, 1)."},"idris2":{"summary":"Idris2 - Fibonacci","value":"fibs : Stream Integer\nfibs = 0 :: 1 :: zipWith (+) fibs (tail fibs)\nmain : IO ()\nmain = printLn $ take 17 fibs\n"},"cpp":{"summary":"C++ - Fibonacci","value":"#include <iostream>\nint main() { int a=0, b=1; while (a<1000) { std::cout << a << \" \"; int tmp=a; a=b; b=tmp+b; } return 0; }\n"},"bash":{"summary":"Bash - Fibonacci","value":"a=0 b=1; while [ $a -lt 1000 ]; do echo -n \"$a \"; tmp=$a; a=$b; b=$((tmp+b)); done"},"haskell":{"summary":"Haskell - Fibonacci","value":"main = putStrLn $ unwords $ map show $ takeWhile (< 1000) fibs where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)"},"raku":{"summary":"Raku - Fibonacci","value":"my ($a, $b) = 0, 1; while $a < 1000 { print \"$a \"; ($a, $b) = $b, $a+$b }"},"elixir":{"summary":"Elixir - Fibonacci","value":"Stream.unfold({0, 1}, fn {a, b} -> {a, {b, a+b}} end) |> Enum.take_while(&(&1 < 1000)) |> Enum.join(\" \") |> IO.puts"},"clojure":{"summary":"Clojure - Fibonacci","value":"(loop [a 0 b 1] (when (< a 1000) (print a \" \") (recur b (+ a b))))"},"rust":{"summary":"Rust - Fibonacci","value":"fn main() { let (mut a, mut b) = (0, 1); while a < 1000 { print!(\"{} \", a); let tmp = a; a = b; b = tmp + b; } }"},"go":{"summary":"Go - Fibonacci","value":"package main\nimport \"fmt\"\nfunc main() { a, b := 0, 1; for a < 1000 { fmt.Print(a, \" \"); a, b = b, a+b } }\n"},"python":{"summary":"Python - Fibonacci","value":"a, b = 0, 1\nwhile a < 1000:\n    print(a, end=' ')\n    a, b = b, a+b\n"},"typescript":{"summary":"TypeScript - Fibonacci","value":"let [a, b] = [0, 1]; while (a < 1000) { process.stdout.write(a + \" \"); [a, b] = [b, a+b]; }"},"cobol":{"summary":"COBOL - Fibonacci","value":"IDENTIFICATION DIVISION.\nPROGRAM-ID. FIB.\nDATA DIVISION.\nWORKING-STORAGE SECTION.\n01 A PIC 9(4) VALUE 0.\n01 B PIC 9(4) VALUE 1.\n01 TMP PIC 9(4).\nPROCEDURE DIVISION.\n  PERFORM UNTIL A >= 1000\n    DISPLAY A \" \" WITH NO ADVANCING\n    MOVE A TO TMP\n    MOVE B TO A\n    ADD TMP TO B\n  END-PERFORM\n  STOP RUN.\n"},"javascript":{"summary":"JavaScript - Fibonacci","value":"let [a, b] = [0, 1]; while (a < 1000) { process.stdout.write(a + \" \"); [a, b] = [b, a+b]; }"},"php":{"summary":"PHP - Fibonacci","value":"<?php $a=0; $b=1; while ($a<1000) { echo \"$a \"; $tmp=$a; $a=$b; $b=$tmp+$b; }"},"jimtcl":{"summary":"JimTcl - Fibonacci","value":"set a 0; set b 1; while {$a < 1000} { puts -nonewline \"$a \"; set tmp $a; set a $b; set b [expr {$tmp + $b}] }"},"awk":{"summary":"AWK - Fibonacci","value":"BEGIN { a=0; b=1; while (a<1000) { printf \"%d \", a; tmp=a; a=b; b=tmp+b; } }"},"fortran":{"summary":"Fortran - Fibonacci","value":"program fib\n  integer :: a=0, b=1, tmp\n  do while (a < 1000)\n    write(*,'(I0,A)',advance='no') a, ' '\n    tmp = a; a = b; b = tmp + b\n  end do\nend program\n"},"d":{"summary":"D - Fibonacci","value":"import std.stdio; void main() { int a=0, b=1; while (a<1000) { write(a, \" \"); int tmp=a; a=b; b=tmp+b; } }"}},"schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"detected_language":"python","exit_code":0,"job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"python","stderr":"","stdout":"Hello from Python!\n","success":true},"schema":{"$ref":"#/components/schemas/RunResponse"}}},"description":"Execution completed"},"400":{"content":{"application/json":{"example":{"error":"Could not detect language from code","success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Empty code or detection failed"}},"summary":"Auto-detect language and execute","tags":["Execution"]}},"/keys/self/contacts":{"get":{"description":"List all contacts associated with the authenticated API key.","responses":{"200":{"content":{"application/json":{"example":{"contacts":[{"created_at":"2025-06-15T10:30:00Z","email":"admin@example.com","invited_by":"user@example.com","role":"owner","verified":true},{"created_at":"2026-01-20T14:00:00Z","email":"dev@example.com","invited_by":"admin@example.com","role":"operator","verified":false}]},"schema":{"properties":{"contacts":{"items":{"$ref":"#/components/schemas/Contact"},"type":"array"}},"type":"object"}}},"description":"Contact list"},"503":{"description":"Portal unavailable"}},"summary":"List contacts","tags":["API Keys"]},"post":{"description":"Add a new contact to the API key. Only owners can manage contacts.\nSends an invitation email with verification link.\n\nRoles:\n- **owner**: Full control (manage contacts, settings, billing)\n- **operator**: Manage services, execute code\n- **reader**: View-only access\n","requestBody":{"content":{"application/json":{"example":{"email":"newdev@example.com","role":"operator"},"schema":{"properties":{"email":{"format":"email","type":"string"},"role":{"default":"reader","enum":["owner","operator","reader"],"type":"string"}},"required":["email"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"contact":{"email":"newdev@example.com","role":"operator","verified":false},"success":true}}},"description":"Contact added and invitation sent"},"400":{"description":"Missing email or invalid role"},"403":{"description":"Only owners can manage contacts"},"409":{"content":{"application/json":{"example":{"error":"Contact already exists for this key"}}},"description":"Contact already exists"}},"summary":"Add contact","tags":["API Keys"]}},"/services/{id}/execute":{"post":{"description":"Run a command inside a running service container. Returns a job ID for polling.\nUse `GET /jobs/{job_id}` to retrieve the result.\n\nSet `timeout: 0` for unlimited execution (up to 7 days).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"simple":{"summary":"Simple command","value":{"command":"systemctl status nginx"}},"unlimited":{"summary":"Unlimited timeout","value":{"command":"./train-model.sh","timeout":0}},"with_files":{"summary":"With input files","value":{"command":"python3 /tmp/script.py","input_files":[{"content":"cHJpbnQoJ2hlbGxvJyk=","filename":"script.py"}]}},"with_timeout":{"summary":"Long-running with timeout","value":{"command":"make build","timeout":300000}}},"schema":{"properties":{"command":{"description":"Shell command to execute","type":"string"},"input_files":{"description":"Files to place in /tmp/ before execution","items":{"properties":{"content":{"description":"Base64-encoded file content","type":"string"},"filename":{"type":"string"}},"required":["filename","content"],"type":"object"},"type":"array"},"timeout":{"default":30000,"description":"Timeout in milliseconds (default 30000, 0 = unlimited up to 7 days)","type":"integer"}},"required":["command"],"type":"object"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"job_id":"ba943906-4ea6-a61c-9980-445f459368d","message":"Command submitted. Poll /jobs/ba943906-4ea6-a61c-9980-445f459368d for result.","status":"pending"}}},"description":"Command submitted for execution"},"400":{"content":{"application/json":{"example":{"error":"Command is required"}}},"description":"Missing command"},"403":{"description":"Not authorized to manage this service"},"404":{"description":"Service not found"},"409":{"content":{"application/json":{"example":{"error":"Service is not running. Wake it first."}}},"description":"Service not running"}},"summary":"Execute command in service","tags":["Services"]}},"/revoke-token":{"post":{"description":"Immediately invalidate a previously minted live token.","requestBody":{"content":{"application/json":{"example":{"token":"unsb-lt-xxxxxxxx"},"schema":{"properties":{"token":{"type":"string"}},"required":["token"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"success":true}}},"description":"Token revoked"},"400":{"description":"Missing token or revocation failed"},"401":{"description":"Missing API key"}},"summary":"Revoke a live token","tags":["API Keys"]}},"/sessions/{id}/unboost":{"post":{"description":"Reduce session back to default vCPU and memory allocation.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"message":"Session returned to base resources","session":{"session_id":"unsb-vm-abc123","status":"running","vcpu":1},"success":true}}},"description":"Session unboosted"},"404":{"description":"Session not found"}},"summary":"Return session to base resources","tags":["Sessions"]}},"/check-domain":{"get":{"description":"Validate whether a domain is allowed for service routing. Checks:\n- Infrastructure domains (always allowed)\n- Service subdomains (*.on.unsandbox.com) — checks if service exists\n- Custom domains — checks if registered to a service\n","parameters":[{"description":"Domain name to check","in":"query","name":"domain","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"infrastructure":{"summary":"Infrastructure domain","value":{"allowed":true,"type":"infrastructure"}},"service":{"summary":"Service subdomain","value":{"allowed":true,"service":"myapp","type":"service"}}}}},"description":"Domain is valid"},"400":{"content":{"application/json":{"example":{"allowed":false,"error":"Invalid domain format"}}},"description":"Invalid domain"},"404":{"content":{"application/json":{"example":{"allowed":false,"error":"Service not found"}}},"description":"Service not found for domain"}},"summary":"Check domain availability","tags":["Domains"]}},"/sessions/{id}":{"delete":{"description":"Destroy the session and its container permanently.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"session_id":"unsb-vm-abc123","status":"terminated"}}},"description":"Session terminated"},"404":{"description":"Session not found"}},"summary":"Terminate session","tags":["Sessions"]},"get":{"description":"Get detailed session information and connection URL.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}},"description":"Session details"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Session not found"}},"summary":"Get session status","tags":["Sessions"]}},"/images/public":{"get":{"description":"Returns all public images (marketplace). No authentication required.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"images":{"items":{"$ref":"#/components/schemas/ImageSummary"},"type":"array"}},"type":"object"}}},"description":"List of public images"}},"summary":"List public images","tags":["Images"]}},"/sessions/{id}/boost":{"post":{"description":"Increase session vCPU and memory. Each vCPU includes 2GB RAM.\nBoosting consumes additional concurrency slots.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"vcpu":4},"schema":{"properties":{"vcpu":{"default":2,"description":"Target vCPU count (default 2)","maximum":8,"minimum":1,"type":"integer"}},"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"example":{"message":"Session boosted to 4 vCPU, 8192 MB RAM","session":{"session_id":"unsb-vm-abc123","status":"running","vcpu":4},"success":true}}},"description":"Session boosted"},"404":{"description":"Session not found"},"429":{"content":{"application/json":{"example":{"error":"concurrency_limit_reached","message":"Cannot boost session: not enough concurrency slots (boost consumes additional slots)"}}},"description":"Concurrency limit reached (boost consumes additional slots)"}},"summary":"Boost session resources","tags":["Sessions"]}},"/snapshots/{id}":{"delete":{"description":"Permanently delete a snapshot.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"snapshot_id":"snap-abc123","status":"deleted"}}},"description":"Snapshot deleted"},"400":{"description":"Snapshot is locked"},"404":{"description":"Snapshot not found"}},"summary":"Delete snapshot","tags":["Snapshots"]},"get":{"description":"Get detailed information about a snapshot.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotResponse"}}},"description":"Snapshot details"},"404":{"description":"Snapshot not found"}},"summary":"Get snapshot details","tags":["Snapshots"]}},"/sessions/{id}/lock":{"post":{"description":"Lock session to prevent accidental deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"locked":true,"session_id":"unsb-vm-abc123"}}},"description":"Session locked"}},"summary":"Lock session","tags":["Sessions"]}},"/images/{id}/lock":{"post":{"description":"Lock an image to prevent accidental deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Image locked"}},"summary":"Lock image","tags":["Images"]}},"/shells":{"get":{"description":"Returns all supported shells and REPLs for interactive sessions, grouped by category.","responses":{"200":{"content":{"application/json":{"example":{"categories":{"data":["r","julia","sqlite3"],"erlang":["erl","iex"],"javascript":["node"],"lisp":["scheme","guile","sbcl","clisp","clojure"],"python":["python","python3","ipython","bpython"],"ruby":["ruby","irb"],"unix":["bash","dash","sh","zsh","fish"]},"count":35,"shells":["bash","bpython","clisp","clojure","csh","dash","elvish","erl","fish","ghci","guile","iex","ipython","irb","julia","ksh","lua","mksh","node","perl","php","posh","python","python3","r","rc","ruby","sbcl","scheme","sh","sqlite3","tcsh","xonsh","yash","zsh"]},"schema":{"$ref":"#/components/schemas/ShellsResponse"}}},"description":"Shell list"}},"summary":"List supported shells","tags":["Languages"]}},"/services/{id}/env/export":{"post":{"description":"Export all environment variables as a .env formatted string.\nRequires HMAC authentication (proves ownership of secret key).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"env":"DATABASE_URL=postgres://localhost/mydb\nDEBUG=true\nAPI_KEY=secret123"}}},"description":"Environment exported"},"403":{"description":"Not authorized to export this vault"},"404":{"description":"Service or vault not found"},"503":{"description":"Portal unavailable"}},"summary":"Export environment variables","tags":["Services"]}},"/jobs":{"get":{"description":"Returns all jobs for the authenticated API key.","responses":{"200":{"content":{"application/json":{"example":[{"created_at":"2025-01-11T12:00:00Z","job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"python","network_mode":"zerotrust","status":"completed"},{"created_at":"2025-01-11T12:01:00Z","job_id":"c1d2e3f4-5678-90ab-cdef-1234567890ab","language":"rust","network_mode":"zerotrust","status":"running"}],"schema":{"items":{"$ref":"#/components/schemas/JobSummary"},"type":"array"}}},"description":"List of jobs"}},"summary":"List all active jobs","tags":["Jobs"]}},"/images/{id}/visibility":{"post":{"description":"Control who can see and use this image.\n\nVisibility options:\n- **private** (default): Only owner can see/use\n- **unlisted**: Hidden from public listing, but can be shared via trust\n- **public**: Visible to all users (marketplace)\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"visibility":"unlisted"},"schema":{"properties":{"visibility":{"enum":["private","unlisted","public"],"type":"string"}},"required":["visibility"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Visibility updated"},"400":{"description":"Invalid visibility value"}},"summary":"Set image visibility","tags":["Images"]}},"/sessions/{id}/restore":{"post":{"description":"Restore session to a previous snapshot state.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"snapshot_id":{"type":"string"}},"required":["snapshot_id"],"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"example":{"session_id":"unsb-vm-abc123","status":"restored"}}},"description":"Session restored"}},"summary":"Restore session from snapshot","tags":["Sessions"]}},"/jobs/{job_id}":{"delete":{"description":"Attempt to cancel a running job. Returns any partial output and compiled artifacts.\nCancellation is best-effort - jobs may complete before cancellation takes effect.\n","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"artifacts":[],"completed_at":"2025-01-11T12:00:30Z","job_id":"ba943906-4ea6-a61c-9980-445f459368d","message":"Job cancelled","status":"cancelled","stdout":"   Compiling hello v0.1.0 (/tmp)\n","success":true},"schema":{"$ref":"#/components/schemas/CancelResponse"}}},"description":"Job cancelled"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Job not running or already completed"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Job not found"}},"summary":"Cancel a running job","tags":["Jobs"]},"get":{"description":"Poll for job completion and retrieve results. Returns immediately with current status.\nResults are flattened to the top level (no nested `result` object).\n","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"cancelled":{"summary":"Job cancelled","value":{"artifacts":[],"completed_at":"2025-01-11T12:00:30Z","created_at":"2025-01-11T12:00:00Z","job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"rust","network_mode":"zerotrust","started_at":"2025-01-11T12:00:01Z","status":"cancelled","stderr":"","stdout":"   Compiling hello v0.1.0 (/tmp)\n","success":false}},"completed":{"summary":"Job completed","value":{"completed_at":"2025-01-11T12:00:02Z","created_at":"2025-01-11T12:00:00Z","exit_code":0,"job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"python","network_mode":"zerotrust","started_at":"2025-01-11T12:00:01Z","status":"completed","stderr":"","stdout":"42\n","success":true,"total_time_ms":236}},"pending":{"summary":"Job pending","value":{"created_at":"2025-01-11T12:00:00Z","job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"python","network_mode":"zerotrust","status":"pending","timeout":60000}},"running":{"summary":"Job running","value":{"created_at":"2025-01-11T12:00:00Z","job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"python","network_mode":"zerotrust","started_at":"2025-01-11T12:00:01Z","status":"running"}}},"schema":{"$ref":"#/components/schemas/JobStatus"}}},"description":"Job found"},"404":{"content":{"application/json":{"example":{"error":"Job not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Job not found"}},"summary":"Get job status and results","tags":["Jobs"]}},"/list-tokens":{"post":{"description":"List all active (non-expired, non-revoked) live tokens for the authenticated API key.","responses":{"200":{"content":{"application/json":{"example":{"tokens":[{"expires_at":"2026-01-20T14:30:00Z","token":"unsb-lt-xxxxxxxx"},{"expires_at":"2026-01-20T15:00:00Z","token":"unsb-lt-yyyyyyyy"}]}}},"description":"Token list"},"401":{"description":"Missing API key"}},"summary":"List active live tokens","tags":["API Keys"]}},"/services/{id}/upgrade/logs":{"get":{"description":"Returns upgrade log output for a service. Optionally limit to last N lines.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Limit to last N lines (default all)","in":"query","name":"lines","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"examples":{"no_upgrade":{"summary":"Not upgrading","value":{"log":"","message":"Service is not upgrading"}},"with_logs":{"summary":"Upgrade logs","value":{"log":"Upgrading packages...\nSetting up linux-base (4.5ubuntu3.8)...\n"}}}}},"description":"Upgrade logs"},"404":{"description":"Service not found"}},"summary":"Get OS upgrade logs","tags":["Services"]}},"/health":{"get":{"description":"Simple health check endpoint.","responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Service is healthy"}},"summary":"Health check","tags":["System"]}},"/images/{id}/transfer":{"post":{"description":"Transfer full ownership of an image to another API key.\nThe image stays on the same LXD node; only the owner_api_key is updated.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"to_api_key":"unsb-pk-xxxx-xxxx-xxxx-xxxx"},"schema":{"properties":{"to_api_key":{"description":"Recipient's public API key","type":"string"}},"required":["to_api_key"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Image transferred"},"404":{"description":"Image or recipient API key not found"}},"summary":"Transfer image ownership","tags":["Images"]}},"/images/owned":{"get":{"description":"Returns only images owned by the authenticated API key. Includes management fields like trusted_keys.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"images":{"items":{"$ref":"#/components/schemas/ImageResponse"},"type":"array"}},"type":"object"}}},"description":"List of owned images"}},"summary":"List owned images","tags":["Images"]}},"/images/{id}/grant":{"post":{"description":"Grant access to a private/unlisted image for a specific API key.\nThe granted user can use the image to spawn services but cannot modify or delete it.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"api_key":"unsb-pk-xxxx-xxxx-xxxx-xxxx"},"schema":{"properties":{"api_key":{"description":"API key to grant access to","type":"string"}},"required":["api_key"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Access granted"},"404":{"description":"Image or target API key not found"}},"summary":"Grant image access","tags":["Images"]}},"/images":{"get":{"description":"Returns all images owned by or shared with the authenticated API key.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"images":{"items":{"$ref":"#/components/schemas/ImageSummary"},"type":"array"}},"type":"object"}}},"description":"List of images"}},"summary":"List images","tags":["Images"]},"post":{"description":"Create an independent LXD image from a service or snapshot.\n\nUnlike snapshots, images:\n- Survive container deletion\n- Can be transferred between API keys\n- Can have visibility settings (public/private/unlisted)\n- Can be shared with specific API keys via trust\n","requestBody":{"content":{"application/json":{"examples":{"from_service":{"summary":"Publish from a service","value":{"description":"Production-ready app image","name":"my-app-v1.0","source_id":"unsb-service-abc123","source_type":"service"}},"from_snapshot":{"summary":"Publish from a snapshot","value":{"name":"backup-before-upgrade","source_id":"unsb-snapshot-xyz789","source_type":"snapshot"}}},"schema":{"$ref":"#/components/schemas/PublishImageRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageResponse"}}},"description":"Image published"},"409":{"description":"Cannot publish (container running, must stop first or use snapshot)"},"429":{"description":"Image storage limit exceeded"}},"summary":"Publish image","tags":["Images"]}},"/services/{id}/lock":{"post":{"description":"Lock service to prevent accidental deletion.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"locked":true}}},"description":"Service locked"}},"summary":"Lock service","tags":["Services"]}},"/execute":{"post":{"description":"Execute code and wait for the result. Blocks until execution completes or times out.\n\nFor compiled languages, you can request the compiled binary artifact by setting `return_artifact: true`.\nFor WASM-compatible languages, set `return_wasm_artifact: true` to get WebAssembly output.\n","requestBody":{"content":{"application/json":{"examples":{"c_with_artifact":{"summary":"C with binary artifact","value":{"code":"#include <stdio.h>\nint main() {\n    printf(\"Hello from artifact!\\n\");\n    return 0;\n}\n","language":"c","return_artifact":true}},"c_with_wasm":{"summary":"C with both native and WASM artifacts","value":{"code":"#include <stdio.h>\nint main() {\n    printf(\"Hello from WASM!\\n\");\n    return 0;\n}\n","language":"c","return_artifact":true,"return_wasm_artifact":true}},"high_cpu":{"summary":"With extra CPU/RAM","value":{"code":"import multiprocessing\nprint(f\"CPUs: {multiprocessing.cpu_count()}\")\n","language":"python","vcpu":4}},"python":{"summary":"Python execution","value":{"code":"print(42)","language":"python"}},"python_with_env":{"summary":"Python with environment variables","value":{"code":"import os\nprint(os.environ.get('MY_VAR', 'not set'))\n","env":{"MY_VAR":"hello world"},"language":"python"}},"with_input_files":{"summary":"With input files","value":{"code":"with open('/tmp/data.txt') as f:\n    print(f.read())\n","input_files":[{"content":"SGVsbG8gV29ybGQh","filename":"data.txt"}],"language":"python"}},"with_network":{"summary":"With network access","value":{"code":"import urllib.request\nprint(urllib.request.urlopen('https://api.github.com').status)\n","language":"python","network_mode":"semitrusted"}}},"schema":{"$ref":"#/components/schemas/ExecuteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"success":{"summary":"Successful execution","value":{"exit_code":0,"job_id":"ba943906-4ea6-a61c-9980-445f459368d","language":"python","network_mode":"zerotrust","stderr":"","stdout":"42\n","success":true,"total_time_ms":236}},"with_artifact":{"summary":"With binary artifact","value":{"artifact":{"data":"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAYBAAAAAA...","filename":"code","type":"base64"},"exit_code":0,"job_id":"c1d2e3f4-5678-90ab-cdef-1234567890ab","language":"c","network_mode":"zerotrust","stderr":"","stdout":"Hello from artifact!\n","success":true,"total_time_ms":1523}},"with_wasm":{"summary":"With WASM artifact","value":{"artifact":{"data":"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAYBAAAAAA...","filename":"code","type":"base64"},"exit_code":0,"job_id":"d2e3f4g5-6789-01bc-def0-234567890abc","language":"c","network_mode":"zerotrust","stderr":"","stdout":"Hello from WASM!\n","success":true,"total_time_ms":2145,"wasm_artifact":{"data":"AGFzbQEAAAABhoCAgAABYAAAAAAAYQQGbWVtb3J5AgAAAAAA...","filename":"code.wasm","type":"base64"}}}},"schema":{"$ref":"#/components/schemas/ExecuteResponse"}}},"description":"Execution completed"},"400":{"content":{"application/json":{"example":{"error":"Missing language or code"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"example":{"error":"Invalid API key"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Authentication failed"},"429":{"content":{"application/json":{"examples":{"concurrency_limit":{"value":{"active_executions":5,"concurrency_limit":5,"error":"concurrency_limit_reached"}},"rate_limit":{"value":{"error":"rate_limit_exceeded","rate_per_minute":60,"reset_at":"2025-01-11T12:00:00Z"}}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate or concurrency limit exceeded"}},"summary":"Execute code synchronously","tags":["Execution"]}},"/sessions":{"get":{"description":"Returns all sessions for the authenticated API key.","responses":{"200":{"content":{"application/json":{"example":{"sessions":[{"network_mode":"zerotrust","remaining_ttl":3540,"session_id":"unsb-vm-abc123","status":"running"},{"network_mode":"semitrusted","remaining_ttl":null,"session_id":"unsb-vm-def456","status":"frozen"}]},"schema":{"properties":{"sessions":{"items":{"$ref":"#/components/schemas/SessionSummary"},"type":"array"}},"type":"object"}}},"description":"List of sessions"}},"summary":"List active sessions","tags":["Sessions"]},"post":{"description":"Create a persistent shell session with WebSocket access.\nSessions provide an interactive container that persists between commands.\n","requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"Default bash session","value":{}},"python_repl":{"summary":"Python REPL","value":{"shell":"python3"}},"with_network":{"summary":"With network access","value":{"network_mode":"semitrusted","ttl":3600}}},"schema":{"$ref":"#/components/schemas/CreateSessionRequest"}}},"required":false},"responses":{"201":{"content":{"application/json":{"example":{"created_at":"2025-01-11T12:00:00Z","expires_at":"2025-01-11T13:00:00Z","network_mode":"zerotrust","session_id":"unsb-vm-abc123","shell":"bash","status":"running","websocket_url":"wss://api.unsandbox.com/sessions/unsb-vm-abc123/shell"},"schema":{"$ref":"#/components/schemas/SessionResponse"}}},"description":"Session created"}},"summary":"Create interactive session","tags":["Sessions"]}},"/sessions/{id}/unfreeze":{"post":{"description":"Wake a frozen session and restore its state.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"session_id":"unsb-vm-abc123","status":"running","unfreeze_time_ms":1523}}},"description":"Session woken"}},"summary":"Wake session","tags":["Sessions"]}},"/services/{id}/unfreeze":{"post":{"description":"Manually wake a frozen service.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"service_id":"svc-abc123","state":"running","unfreeze_time_ms":2341}}},"description":"Service woken"}},"summary":"Wake service","tags":["Services"]}},"/services/{id}/logs":{"get":{"description":"Get bootstrap and application logs for the service.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"log":"Starting bootstrap...\napt-get update\n..."}}},"description":"Service logs"}},"summary":"Get service logs","tags":["Services"]}},"/sessions/{id}/execute":{"post":{"description":"Run a command in the session's container and return output.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"command":"ls -la /tmp"},"schema":{"properties":{"command":{"type":"string"}},"required":["command"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"exit_code":0,"stderr":"","stdout":"total 0\ndrwxrwxrwt 2 root root 40 Jan 11 12:00 .\n"}}},"description":"Command executed"}},"summary":"Execute command in session","tags":["Sessions"]}},"/services/{id}/snapshot":{"post":{"description":"Create a snapshot of the service's container state.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotResponse"}}},"description":"Snapshot created"}},"summary":"Create service snapshot","tags":["Services"]}},"/services/{id}/env":{"delete":{"description":"Remove specific environment variables from the service.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"keys":["DEBUG","VERBOSE"]},"schema":{"properties":{"keys":{"items":{"type":"string"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"deleted":["DEBUG","VERBOSE"],"success":true}}},"description":"Variables deleted"}},"summary":"Delete service environment variables","tags":["Services"]},"get":{"description":"Retrieve all environment variables set for the service.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"env":{"API_KEY":"secret123","DATABASE_URL":"postgres://..."}}}},"description":"Environment variables"}},"summary":"Get service environment variables","tags":["Services"]},"put":{"description":"Set or update environment variables for the service.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"env":{"DATABASE_URL":"postgres://localhost/mydb","DEBUG":"true"}},"schema":{"properties":{"env":{"additionalProperties":{"type":"string"},"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"env":{"DATABASE_URL":"postgres://localhost/mydb","DEBUG":"true"},"success":true}}},"description":"Environment updated"}},"summary":"Set service environment variables","tags":["Services"]}},"/keys/validate":{"post":{"description":"Validate your API key pair and retrieve its configuration including rate limits, concurrency limits, and expiration status.\n\nThis is useful for checking if your key pair is valid, viewing your current limits, or building key management interfaces.\n\n**Authentication**: Uses standard HMAC authentication (same as all other endpoints).\n","requestBody":{"content":{"application/json":{"example":{},"schema":{"properties":{},"type":"object"}}},"description":"Optional payload (can be empty object)"},"responses":{"200":{"content":{"application/json":{"example":{"burst":10,"concurrency_limit":5,"expires_at":"2026-12-31T23:59:59Z","public_key":"unsb-pk-xxxx-xxxx-xxxx-xxxx","rate_per_minute":60,"tier":"Tier 3","valid":true},"schema":{"properties":{"burst":{"description":"Burst capacity for rate limiting","type":"integer"},"concurrency_limit":{"description":"Maximum concurrent executions","type":"integer"},"expires_at":{"description":"Key expiration timestamp (ISO 8601)","format":"date-time","nullable":true,"type":"string"},"public_key":{"description":"Public key identifier","type":"string"},"rate_per_minute":{"description":"Maximum requests per minute","type":"integer"},"tier":{"description":"Subscription tier name","type":"string"},"valid":{"description":"Whether the key is valid","type":"boolean"}},"type":"object"}}},"description":"API key is valid"},"401":{"content":{"application/json":{"example":{"error":"Invalid API key","valid":false},"schema":{"properties":{"error":{"type":"string"},"valid":{"type":"boolean"}},"type":"object"}}},"description":"Invalid API key or signature"}},"security":[{"bearerAuth":[]}],"summary":"Validate API key pair","tags":["API Keys"]}},"/images/shared":{"get":{"description":"Returns images shared with you via trusted_keys (images you can use but don't own).","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"images":{"items":{"$ref":"#/components/schemas/ImageSummary"},"type":"array"}},"type":"object"}}},"description":"List of shared images"}},"summary":"List shared images","tags":["Images"]}},"/sessions/{id}/freeze":{"post":{"description":"Freeze the session to save resources. Container state is preserved.\nSession can be woken later with all state intact.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"session_id":"unsb-vm-abc123","status":"frozen"}}},"description":"Session frozen"}},"summary":"Sleep session","tags":["Sessions"]}}},"security":[{"bearerAuth":[]}],"servers":[{"description":"Production server","url":"https://api.unsandbox.com"}],"tags":[{"description":"Code execution endpoints","name":"Execution"},{"description":"Job management and status","name":"Jobs"},{"description":"Supported languages","name":"Languages"},{"description":"Interactive shell sessions","name":"Sessions"},{"description":"Persistent long-running services","name":"Services"},{"description":"State snapshots for sessions and services (tied to container lifecycle)","name":"Snapshots"},{"description":"Independent, transferable container images (survive container deletion)","name":"Images"},{"description":"API key management, contacts, audit log, and live tokens","name":"API Keys"},{"description":"Domain routing and validation","name":"Domains"},{"description":"System health and cluster status","name":"System"}]}