shellbox SSH API

Programmatic Linux VM management over SSH. No REST endpoints, no API tokens, no SDK. Your SSH key authenticates every call. Add --json to any command for structured output.

Contents
Overview Authentication Quickstart Box Management Modes OCI Images Billing & Payments Key Management Connecting Scripting Patterns

# Overview

Every shellbox operation is an SSH command. Append --json for machine-readable JSON output. The protocol is SSH — use any language that can shell out or has an SSH library.

# human-readable
$ ssh shellbox.dev list

# machine-readable
$ ssh shellbox.dev list --json
{"boxes": [{"name": "mybox", "state": "running", ...}]}

No API keys to rotate. No OAuth flows. No request signing. Your SSH key is the credential.

# Authentication

Your SSH public key is your identity. The first time you connect, an account is created automatically. No signup, no email, no password.

# all commands go through a single endpoint
$ ssh shellbox.dev <command> [args] [--json]

# Quickstart

# create a box
$ ssh shellbox.dev create mybox --json
{
  "name": "mybox",
  "id": "a1b2c3d4-...",
  "size": 1,
  "backend": "fc",
  "url": "https://mybox-a1b2c3d4.shellbox.dev",
  "email": "mybox-a1b2c3d4@in.shellbox.dev",
  "connect": "ssh mybox@shellbox.dev"
}

# connect (interactive SSH session)
$ ssh mybox@shellbox.dev

# run a command non-interactively
$ ssh mybox@shellbox.dev -- uname -a
Linux mybox 6.1.0 ...

# delete when done
$ ssh shellbox.dev delete mybox --json
{"name": "mybox", "status": "deleted"}

# Box Management

create <name> [xN] [--fc|--ch] --json
Create a new stock box. Size x1–x8 (default x1). Backend: Firecracker (default) or Cloud Hypervisor.
Response
name string · id string · size integer · backend fc | ch · url string · email string · connect string
list --json
List all your boxes.
Response
boxes array of:
name string · id string · size integer · source stock | oci · backend fc | ch
state running | stopped | stopping · mode stop | keepalive | wakeup | cron
url string | null · email string | null
idle_timeout_min integer | null · cron_interval_min integer | null · cron_runtime_min integer | null
show <name> --json
Detailed box metadata.
Response
name string | null · id string · state running | stopped | stopping
size integer · backend fc | ch · backend_label string · source stock | oci
url string | null · email string | null · mode stop | keepalive | wakeup | cron
image_ref string | null · image_digest string | null
duplicate <source> <name> --json
Clone a stopped box (inherits size).
Response
name string · source string · size integer · url string · connect string
rename <name> <new-name> --json
Rename a box.
Response
old_name string · new_name string · url string · email string
stop <name> --json
Force-stop a box (clears keepalive, preserves wakeup/cron).
Response
name string · status stopping | already_stopped | already_stopping · mode_preserved wakeup | cron | null
delete <name> --json
Delete a box permanently.
Response
name string · status "deleted"

# Modes

Control what happens when you disconnect or when traffic arrives.

keepalive <name> --json
Toggle keepalive — box stays running after disconnect.
Response
name string · keepalive boolean · box_stopped boolean · box_started boolean
wakeup <name> [idle_minutes] --json
Toggle wakeup — box auto-starts on HTTP request, stops after idle timeout.
Response
name string · wakeup boolean · idle_timeout_min integer | null · box_stopped boolean
cron <name> <interval_min> [runtime_min] --json
Toggle cron — box wakes on schedule, hits webhook, stops.
Response
name string · cron boolean · interval_min integer | null · runtime_min integer | null · box_stopped boolean

# OCI Images

Create boxes from Docker/OCI images. The image is prepared into a bootable VM with SSH access.

image prepare <image-ref> --json
Prepare an OCI image for use. Asynchronous — poll with image status.
Response
display_ref string · digest string · status string · state string · error string | null
image status <image-ref> --json
Check preparation status.
Response
display_ref string · canonical_ref string · status string | null · digest string
architecture string · guest_layer_version string · error string | null
create-from-oci <name> <image-ref> [xN] [--fc|--ch] --json
Create a box from a prepared OCI image.
Response
name string · id string · size integer · backend fc | ch
image_ref string · image_digest string · url string · email string · connect string

# Billing & Payments

billing --json
Account balance, usage costs, and per-box burn rates.
Response
balance number · funds_added number · funds_refunded number · usage_cost number
hourly_rate number · remaining_hours number | null
pending_refunds array of {amount, status, created_at}
boxes array of {name, size, state, hourly_rate}
funds <amount> --json
Add funds (min $10). Returns a checkout URL.
Response
amount number · checkout_url string
payments --json
Payment history.
Response
pending array of {amount, created_at}
recent array of {amount, timestamp}
refund <amount> --json
Request a refund (within 3 months of payment).
Response
amount number · status "pending"
promocode <code> --json
Redeem a promo code for free credits.
Response
code string · added number · balance number

# Key Management

key list --json
List SSH keys linked to your account.
Response
keys array of:
fingerprint string · type string · comment string · current boolean
key add "<public-key>" --json
Link an additional SSH key to your account.
Response
fingerprint string · type string · comment string · action "added"
key remove <fingerprint> --json
Remove an SSH key from your account.
Response
fingerprint string · action "removed"

# Connecting to Boxes

Box connections use SSH with the box name as the username:

# interactive shell
$ ssh mybox@shellbox.dev

# run a command
$ ssh mybox@shellbox.dev -- ls /root

# file transfer
$ scp file.txt mybox@shellbox.dev:/root/
$ scp mybox@shellbox.dev:/root/output.txt ./
$ sftp mybox@shellbox.dev

# port forwarding
$ ssh -L 8080:localhost:8080 mybox@shellbox.dev
$ ssh -R 9090:localhost:9090 mybox@shellbox.dev

Connecting to a stopped box automatically starts it. Disconnecting pauses it (unless keepalive/wakeup/cron is set).

# Scripting Patterns

Bash

#!/bin/bash
# create a box, run a build, tear down
BOX=$(ssh shellbox.dev create ci-$RANDOM --json | jq -r .name)
ssh "$BOX@shellbox.dev" -- bash -c 'cd /root && git clone ... && make test'
ssh shellbox.dev delete "$BOX" --json

Python

# using subprocess
import subprocess, json

result = subprocess.run(
    ["ssh", "shellbox.dev", "list", "--json"],
    capture_output=True, text=True
)
boxes = json.loads(result.stdout)["boxes"]
running = [b for b in boxes if b["state"] == "running"]

Agent / LLM tool use

# give your agent a sandbox
$ ssh shellbox.dev create agent-sandbox --json
# agent runs commands via SSH
$ ssh agent-sandbox@shellbox.dev -- pip install -r requirements.txt
$ ssh agent-sandbox@shellbox.dev -- python run_task.py
# public URL for webhooks/preview
$ ssh agent-sandbox@shellbox.dev -- 'python -m http.server 80 &'
# https://agent-sandbox-a1b2c3d4.shellbox.dev is live

Full schema reference available at runtime:

$ ssh shellbox.dev help --json

Stability guarantee: The --json output is a stable interface. Fields are only added, never removed or renamed. Types don't change. If a breaking change is ever necessary, it will ship under a new flag (--json-v2) and the original --json output will continue to work unchanged.