Migrate from boat.dev#

The TaskCloud REST API follows the resource model of boat.dev's API (sandboxes, commands, files, hosted ports, snapshots, webhooks), so most code ports directly. The main differences:

  • Field names are snake_case.
  • "Stop" becomes pause, and pause keeps RAM.
  • Idle sandboxes pause automatically (default after 5 min) and wake on request, so you pay for active seconds, not for the time until an auto-stop timer fires.

boat.dev compatibility adapter: Coming soon. Until it ships, use the mapping below. The boat.dev details here come from its public documentation as of 2026-11; check boat.dev's current docs for exact behavior.

Key differences#

boat.dev TaskCloud
Base URL https://boat.dev/api/v1 https://api.task.cloud/v1
JSON style camelCase, {"ok": true, "type": ...} envelope snake_case, plain resource objects
Errors {"ok": false, "code", "message", "error": {...}, "requestId"} {"error": {"code", "message", "retryable", "status", "request_id", "details"}}
Stop / resume Stop saves a disk snapshot; resume boots again Pause snapshots RAM and disk; resume restores the running state (target p95 < 800 ms)
Auto-stop TTL-based auto-stop Auto-pause when idle (default 5 min) plus wake on request (HTTP, SSH, API)
Fork From the last disk snapshot From the live VM including memory (target < 2 s)
Billing Per second while the VM runs (until you stop it or its auto-stop timer fires) Per second while running; $0 compute while paused
Delete Requires the X-Ascii-Confirm-Delete header Plain DELETE (no confirmation header)
Idempotency idempotencyKey field Idempotency-Key header
Rate-limit headers RateLimit-Policy / RateLimit Same headers (IETF draft), with policies default and starts

Endpoint mapping#

boat.dev TaskCloud Notes
POST /sandboxes (type, ttlSeconds, from, hostedPorts) POST /sandboxes (size, ttl_seconds, template or snapshot_id, ports) small / default / large map directly. xlarge has no equivalent yet.
GET /sandboxes, GET /sandboxes/{id} same paths Filters: state, label=key=value, name_prefix
PATCH /sandboxes/{id} (extend) PATCH /sandboxes/{sandbox_id} ttl_seconds, auto_pause, always_on
POST /sandboxes/{id}/stop POST /sandboxes/{sandbox_id}/pause RAM is kept
POST /sandboxes/{id}/resume POST /sandboxes/{sandbox_id}/resume Usually not needed: requests wake the sandbox automatically. The size can't change on resume.
POST /sandboxes/{id}/fork POST /sandboxes/{sandbox_id}/fork Includes memory. Same size as the source. Bulk fork: count up to 50 per call, all or nothing.
DELETE /sandboxes/{id} DELETE /sandboxes/{sandbox_id} Returns 202
POST /sandboxes/{id}/commands (command, timeoutSeconds, detached, stream) POST /sandboxes/{sandbox_id}/exec (command, timeout_seconds, background, stream) Sync max 600 s. Background has no limit. Stream is SSE.
GET /sandboxes/{id}/commands/{processId} and .../stream GET .../commands/{command_id} and .../stream Kill: POST .../commands/{command_id}/kill
GET / PUT / DELETE /sandboxes/{id}/files GET / PUT /sandboxes/{sandbox_id}/files/content, DELETE /sandboxes/{sandbox_id}/files Read limit 1 GiB per request (boat.dev: 5 MiB)
GET .../files/list, .../files/info GET .../files, GET .../files/stat
POST .../files/folder, .../files/move POST .../files/mkdir, .../files/move
POST .../files/upload-url, .../download-url same paths Up to 10 GiB; URLs valid 15 min by default, 1 h max
POST /sandboxes/{id}/host (port, public) POST /sandboxes/{sandbox_id}/ports (port, visibility) URL https://<short_id>-<port>.taskhost.cloud
POST /sandboxes/{id}/desktop POST /sandboxes/{sandbox_id}/desktop KasmVNC signed URL with ttl_seconds, read_only. Screenshot and input endpoints are also available.
POST /sandboxes/{id}/sshkey POST /sandboxes/{sandbox_id}/ssh or account-wide POST /ssh-keys Gateway ssh.taskhost.cloud
GET / POST /saved-snapshots POST /sandboxes/{sandbox_id}/snapshots, GET /snapshots Turn a snapshot into a reusable template with POST /templates
GET /sandboxes/{id}/usage GET /sandboxes/{sandbox_id}/usage Also account-wide: GET /usage?group_by=sandbox
GET /limits GET /limits
GET / POST /api-keys, POST /api-keys/scoped GET / POST /api-keys Presets read-only, full-sandbox, ci, admin are kept; restrict a key with restrict.sandbox_ids / restrict.labels
GET / POST /webhooks, POST /webhooks/{id}/rotate GET / POST /webhooks, POST /webhooks/{webhook_id}/rotate-secret See below

Webhooks#

boat.dev event TaskCloud event
sandbox.ready sandbox.ready (new sandbox) and sandbox.resumed (after pause)
sandbox.error sandbox.error
sandbox.archived (stopped) sandbox.paused
— sandbox.deleted
sandbox.hydrated, sandbox.degraded, sandbox.recovered No equivalent. Resume restores memory and disk together, so there is no separate hydration step.

The signature scheme is the same shape: hex HMAC-SHA256(secret, id + "." + timestamp + "." + raw_body), prefixed v1=, with a 300 s window. Only the header names change:

boat.dev TaskCloud
X-Ascii-Delivery Webhook-Id
X-Ascii-Timestamp Webhook-Timestamp
X-Ascii-Signature Webhook-Signature
X-Ascii-Event Webhook-Event
X-Ascii-Attempt Webhook-Attempt

The payload uses created_at, previous_state and state (instead of camelCase), and adds reason. See Webhooks.

CLI mapping#

boat taskcloud
boat login taskcloud login
boat new --type default taskcloud create --size default
boat new --from <snapshot> taskcloud create --snapshot <snapshot_id> or --template <name>
boat list / boat info <id> taskcloud list / taskcloud get <id>
boat exec <id> -- npm test taskcloud exec <id> -- npm test
boat ssh <id> taskcloud ssh <id>
boat stop <id> taskcloud pause <id>
boat resume <id> taskcloud resume <id>
boat fork <id> taskcloud fork <id>
boat host <id> 3000 --public taskcloud port expose <id> 3000 --public
boat desktop <id> taskcloud desktop <id> --open
boat delete <id> taskcloud delete <id>

See CLI for the full reference.

Example: create, run, stop → create, run, (auto-)pause#

# boat.dev
curl -X POST https://boat.dev/api/v1/sandboxes -H "Authorization: Bearer $BOAT_API_KEY" \
  -H "Content-Type: application/json" -d '{"ttlSeconds":3600}'

# TaskCloud
curl -X POST https://api.task.cloud/v1/sandboxes -H "Authorization: Bearer $TASKCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template":"base","size":"default","auto_pause":{"enabled":true,"idle_timeout_seconds":300}}'

curl -X POST https://api.task.cloud/v1/sandboxes/$SANDBOX_ID/exec -H "Authorization: Bearer $TASKCLOUD_API_KEY" \
  -H "Content-Type: application/json" -d '{"command":"echo hello","timeout_seconds":30}'
# No explicit stop needed: after 5 idle minutes the sandbox pauses; the next request wakes it.

Not available (yet)#

boat.dev feature Status on TaskCloud
Built-in agent harnesses (boat prompt, conversations, steer/interrupt) Not planned. We are infrastructure: run Claude Code, Codex or your own agent inside the sandbox.
AI credential profiles and AI key proxy Roadmap
Environments with repositories, setup scripts and secrets Use templates (from an image or snapshot) plus env at creation
Nested virtualization (/dev/kvm) Roadmap (separate class on Cloud Hypervisor)
OpenTelemetry export Not in the MVP. Use webhooks and the usage API.
xlarge size Not available. The largest size is large (8 vCPU / 16 GB).

Cost comparison#

Hourly price for 4 vCPU / 8 GB, according to battleships.dev as of 2026-10: boat.dev $0.036 per running hour. TaskCloud default is $0.030 per active hour, and $0 compute while paused.

The list prices are close, so the difference comes from how long a VM stays billed after the work stops:

  • boat.dev stops a VM on a timer you set (default 1 h). Until the timer fires, the VM is running and billed, and resuming it boots the machine again.
  • TaskCloud pauses an idle VM after 5 minutes by default, keeps its RAM, and resumes it on the next request.

How much that saves depends on your session pattern and auto-stop setting. Paste a usage export into the bill calculator to see both bills side by side.

See Billing for how active time is measured.