# DaytoNah > Sandbox cloud for AI agents on bare metal. Cloud Hypervisor microVMs, one process per sandbox, hardware isolation. SDKs in TypeScript/Python plus a compiled `dnah` CLI. E2B SDK is drop-in compatible — just point `E2B_API_URL` at us. Live: http://51.159.202.231:3000 · admin panel at /_admin/ · token: dev_admin_token_change_me ## Auth All `/v1/*` endpoints require `Authorization: Bearer `. Token comes from the API keys page in the admin panel. ## Core endpoints (full reference) - POST /v1/sandboxes — create sandbox. Body: `{template, cpu, ram_mb, disk_gb, env, language, auto_stop_minutes, auto_archive_days, auto_delete_days, ssh_keys, volume_ids, gpus}`. Accepts E2B's `{templateID, metadata, envVars}` shape too. - GET /v1/sandboxes — list (org-scoped). Query: `?state=running`, `?limit=`. - GET /v1/sandboxes/:id — read. - DELETE /v1/sandboxes/:id — delete. - POST /v1/sandboxes/:id/exec — direct TCP exec (~8 ms P50). Body: `{cmd: [argv], timeout_ms}`. - POST /v1/sandboxes/:id/run-code — run Python/Bash/Node inline. Body: `{code, lang?, timeout_ms}`. `lang` falls back to sandbox.language (default python). - POST /v1/sandboxes/:id/stop · pause — freeze to disk. Aliases. - POST /v1/sandboxes/:id/start · resume — restore (auto-unarchives). - POST /v1/sandboxes/:id/archive — tar+zstd cold storage. - POST /v1/sandboxes/:id/migrate — cross-host move. - POST /v1/sandboxes/:id/snapshot — live snapshot (~25 ms). - POST /v1/sandboxes/:id/restore — restore THIS sandbox from a snapshot. - POST /v1/sandboxes/:id/clone — new sandbox from existing snapshot. - POST /v1/sandboxes/:id/fork — ★ snapshot + clone in one call (66 ms total). Cube says "coming soon"; we ship it. - POST /v1/sandboxes/:id/expose — `{port, public, ttl_seconds}` → URL + HMAC token. - DELETE /v1/sandboxes/:id/expose/:port — revoke. - POST /v1/sandboxes/:id/egress-policy — `{mode: "allow"|"deny", cidrs: [...]}`. nftables firewall on the sandbox's TAP. - GET /v1/sandboxes/:id/metrics — `{cpu_count, mem_total_mb, mem_used_mb, load_1m, disk_used_mb, age_seconds, state, last_activity_at}`. - GET /v1/sandboxes/:id/terminal — WebSocket → in-VM PTY. - POST /v1/sandboxes/:id/ssh-keys — rotate authorized_keys. ## Files - PUT /v1/sandboxes/:id/files?path=… — streaming upload (≤ 256 MB). - GET /v1/sandboxes/:id/files?path=… — download. - GET /v1/sandboxes/:id/files/stat — stat. - GET /v1/sandboxes/:id/files/list?path= — readdir. - POST /v1/sandboxes/:id/files/mkdir?path=&mode= — mkdir -p. - DELETE /v1/sandboxes/:id/files?path=&recurse=true|false — rm. - GET /v1/sandboxes/:id/files/find?path=&pattern=&max= — find filenames matching glob. - GET /v1/sandboxes/:id/files/grep?path=&pattern=&max= — recursive grep. - POST /v1/sandboxes/:id/files/replace — body: `{path, find, replace, glob}`. sed -i across matching files. ## Sessions (persistent shell with sticky cwd) - POST /v1/sandboxes/:id/sessions — create. Body: `{cwd}`. Returns `{id, cwd}`. - GET /v1/sandboxes/:id/sessions — list for this sandbox. - DELETE /v1/sandboxes/:id/sessions/:sid. - POST /v1/sandboxes/:id/sessions/:sid/exec — body: `{cmd, timeout_ms}`. Returns `{command_id, stdout, stderr, exit_code, cwd}`. `cd` inside the cmd persists to the next exec. - GET /v1/sandboxes/:id/sessions/:sid/commands — last 100 commands' output. ## Git (toolbox-style, in-sandbox) - POST /v1/sandboxes/:id/git/clone — `{url, path, branch?, depth?, username?, password?}`. - GET /v1/sandboxes/:id/git/status?path=. - POST /v1/sandboxes/:id/git/add — `{path, files: [...]}`. - POST /v1/sandboxes/:id/git/commit — `{path, message, author_name?, author_email?}`. - POST /v1/sandboxes/:id/git/push · pull — `{path, remote?, branch?, username?, password?}`. - GET /v1/sandboxes/:id/git/branches?path=. - POST /v1/sandboxes/:id/git/checkout — `{path, ref}`. - GET /v1/sandboxes/:id/git/log?path=&limit=. ## Templates / images - GET /v1/templates — list (state, image, content_hash, build_logs). - POST /v1/templates — register an existing rootfs path (admin only). - POST /v1/templates/from-image — ★ build from a Docker / OCI image (admin only). Body: `{name, image, entrypoint?, version?, default_cpu, default_ram_mb, default_disk_gb, size_mb}`. Floating tags (latest, lts, stable, ...) are rejected. Returns 202; poll `GET /v1/templates` for `state: building → ready` (or `failed` with `build_logs`). - POST /v1/templates/from-snapshot — promote a snapshot. ## Volumes - GET · POST /v1/volumes - DELETE /v1/volumes/:id ## Webhooks (HMAC-signed lifecycle events) - POST /v1/webhooks — body: `{url, events: ["*"|"sandbox.state_updated"|"template.state_updated"|...], secret?}`. Returns `{id, secret_returned_once}`. - GET /v1/webhooks — list (secrets redacted). - DELETE /v1/webhooks/:id. Headers on each delivery: `x-dnah-event`, `x-dnah-delivery-id`, `x-dnah-signature: sha256=` (HMAC-SHA-256 of body with the secret). ## Billing / observability - GET /v1/billing/usage[?since_ms&org_id] — per-org roll-up: units, micros, USD. - GET /metrics — Prometheus exposition: `dnah_hosts_*`, `dnah_sandboxes{state=...}`, `dnah_commands{status=...}`, `dnah_billing_micros_last_hour`. - GET /health. ## Admin (org-scoped) - /_admin/ — htmx + xterm + React admin panel (login required). IP-allowlistable via `ADMIN_PANEL_ALLOW=10.0.0.0/8`. - POST /internal/hosts/:id/state — drain / quarantined / ready. ## TS SDK example ```ts import { DaytoNah } from "@daytonah/sdk"; const dn = new DaytoNah({ url: "http://51.159.202.231:3000", token: "" }); const sbx = await dn.sandboxes.create({ template: "dnah-base", ram_mb: 256, language: "bash", env: { OPENAI_API_KEY: process.env.OPENAI_API_KEY! }, auto_stop_minutes: 30, }); await sbx.waitRunning(); const { stdout } = await sbx.exec(["uname", "-a"]); // Code interpreter, language inferred from sandbox const rc = await dn.runCode(sbx.id, "echo hello-from-bash"); // Persistent shell const { id: sid } = await dn.sessionCreate(sbx.id, { cwd: "/tmp" }); await dn.sessionExec(sbx.id, sid, "cd /etc && pwd"); // cwd persists for next exec await dn.sessionExec(sbx.id, sid, "pwd"); // prints /etc ``` ## E2B SDK drop-in Set `E2B_API_URL=http://51.159.202.231:3000` and the E2B JS/Py SDKs work unchanged. We accept their `{templateID, metadata, envVars}` body, expose `/pause`+`/resume`, `GET /v1/sandboxes` list. ## Reproducing perf ``` python3 verify/perf-concurrent-py.py 50 # ~13 ms avg · 17 ms P95 · 552 sbx/sec at 50-concurrent bash verify/p0-features-e2e.sh # all P0 features green ``` ## More - Repo: https://github.com/kubet/daytonah - Research: research/daytona-features.md, research/e2b-features.md, research/gap-analysis.md - Spec audit: bash verify/spec-audit.sh (75 PASS · 1 PARTIAL · 1 FAIL)