Skip to content

Latest commit

 

History

History
352 lines (265 loc) · 10.9 KB

File metadata and controls

352 lines (265 loc) · 10.9 KB

exe.dev API Reference Notes

This file records the exe.dev API documentation that this repository depends on. It was last checked on 2026-07-10 from these source pages:

Each page is also available as raw markdown by appending .md to the URL, for example https://exe.dev/docs/https-api.md. The full command list lives in the CLI reference at https://exe.dev/docs/section/10-cli-reference.

API shape

exe.dev exposes two programmatic access styles:

  1. SSH command automation (the primary API):

    ssh exe.dev ls --json
    ssh exe.dev new --json
  2. HTTPS command automation:

    POST https://exe.dev/exec

POST /exec is not a resource-style REST API. The request body is the same exe.dev command that would be typed into ssh exe.dev or run through ssh exe.dev <command>. API responses enable JSON output by default, equivalent to passing --json.

Example ls --json VM object shape:

{
  "https_url": "https://bloggy.exe.xyz",
  "region": "lon",
  "region_display": "London, UK",
  "ssh_dest": "bloggy.exe.xyz",
  "status": "running",
  "vm_name": "bloggy"
}

Minimal HTTPS request:

curl -X POST https://exe.dev/exec \
  -H "Authorization: Bearer $EXE_DEV_API_KEY" \
  -d 'whoami'

Operational limits:

  • Only POST is accepted.
  • There is no stdin and no pty.
  • Request bodies are limited to 64KB.
  • Commands time out after 30 seconds.
  • Commands that require interactive input do not fit this API.

Any command can be introspected without side effects by passing --help (for example new --help), which returns its flags and examples as JSON.

exe.dev API tokens

The exe.dev HTTPS API uses bearer tokens. A token can be generated by exe.dev:

ssh exe.dev ssh-key generate-api-key --exp=30d

Tokens can also be created locally by signing permissions JSON with an SSH private key. For automation, prefer a dedicated SSH key so the API token family can be revoked without disrupting normal user SSH access.

ssh-keygen -t ed25519 -C api -f ~/.ssh/exe_dev_api
cat ~/.ssh/exe_dev_api.pub | ssh exe.dev ssh-key add

Local token creation flow:

b64url() { tr -d '\n=' | tr '+/' '-_'; }

export PERMISSIONS='{}'
export PAYLOAD=$(printf '%s' "$PERMISSIONS" | base64 | b64url)
export SIG=$(printf '%s' "$PERMISSIONS" | ssh-keygen -Y sign -f ~/.ssh/exe_dev_api -n v0@exe.dev)
export SIGBLOB=$(echo "$SIG" | sed '1d;$d' | b64url)
export EXE_DEV_API_KEY="exe0.$PAYLOAD.$SIGBLOB"

PERMISSIONS is embedded in the token as plaintext JSON. Do not put secrets in it.

Supported top-level permission fields:

  • exp: UTC Unix timestamp after which the token is invalid. The default is the distant future (never expires); exe.dev strongly recommends always setting exp.
  • nbf: UTC Unix timestamp before which the token is not valid yet.
  • cmds: exe.dev command names this token may run. cmds controls command names only; flags, arguments, and options (like --json) are always allowed when the base command is permitted.
  • ctx: signed JSON context uninterpreted by exe.dev. Must itself be valid JSON complying with the restrictions below.

The empty object {} uses defaults. For least-privilege automation, specify cmds explicitly. Subcommands must be granted explicitly as a single string such as "ssh-key list"; allowing ssh-key does not allow ssh-key list.

The default cmds grant is:

  • help
  • ls
  • new
  • whoami
  • ssh-key list
  • share show
  • exe0-to-exe1
  • team
  • team members

Commands such as rm, rename, restart, share port, share set-public, and share set-private should be added only when automation needs them.

Permission JSON restrictions (also enforced inside ctx):

  • Compact JSON is recommended (pipe through jq -c).
  • No leading/trailing whitespace.
  • No newlines or null bytes.
  • No duplicate keys, at any level.
  • Only exp, nbf, cmds, and ctx are allowed at the top level.
  • exp and nbf must be plain integers (no decimals, no exponents) between 2000-01-01 (946684800) and 2100-01-01 (4102444800) UTC.
  • The whole token must not exceed 8KB.

There is no built-in replay protection (no nonce or jti). Use short-lived tokens (small exp) to limit the replay window, and separate SSH keys per token family for revocability.

Short opaque exe1 tokens can be issued from a valid exe0 token:

ssh exe.dev exe0-to-exe1 "$EXE_DEV_API_KEY"

For a VM-scoped token, validate the source token against the VM:

ssh exe.dev exe0-to-exe1 --vm=vm-name "$EXE_DEV_API_KEY"

exe1 tokens work everywhere exe0 tokens work, in exactly the same way. An exe1 token is validated through its underlying exe0 token on every use; to revoke an exe1 token, revoke the underlying exe0 token.

HTTPS error handling

Common responses from POST /exec:

  • 400: request body is empty, missing, or has invalid command syntax (e.g. unbalanced quotes).
  • 401: token is malformed, expired, signed by an unknown key, or fails signature verification.
  • 403: token permissions do not allow the requested command.
  • 404: unknown exe.dev command; check ssh exe.dev help for the full list.
  • 405: non-POST method.
  • 413: request body exceeds 64KB.
  • 422: command ran and returned a non-zero exit code; the body contains the error message.
  • 429: per-key rate limit; use separate SSH keys for independent workloads.
  • 500: unexpected server-side error.
  • 504: command exceeded the 30-second timeout.

Debug checklist for 401:

  • Confirm the signing public key is listed with ssh exe.dev ssh-key list.
  • Confirm exp is not in the past.
  • Confirm the exact compact JSON payload was signed byte-for-byte; avoid editors that add trailing newlines.
  • Use a private key file with ssh-keygen -Y sign -f; an agent-only key is not enough for this command. If the key only lives in ssh-agent, export the public part with ssh-add -L and use the private key file directly.

Debug checklist for 403:

  • Decode the base64url payload and inspect cmds.
  • Remember that subcommands are exact command-name grants.
  • Add only the missing command, then regenerate the token.

VM HTTPS tokens

The exe.dev HTTPS auth proxy can accept bearer tokens for programmatic access to individual VM HTTPS endpoints (API servers, git push over HTTPS). This is separate from authenticating to POST https://exe.dev/exec.

Generate a VM token through exe.dev:

ssh exe.dev ssh-key generate-api-key --vm=my-vm --label=deploy

Generate a VM token locally by changing the SSH signing namespace from v0@exe.dev to v0@VMNAME.exe.xyz:

export SIG=$(printf '%s' "$PERMISSIONS" | ssh-keygen -Y sign -f ~/.ssh/exe_dev_api -n v0@myvm.exe.xyz)

VM token differences:

  • The signing namespace scopes the token to one VM.
  • The token payload ctx is forwarded verbatim to the VM HTTP server as X-ExeDev-Token-Ctx. Its contents are signed, so the VM server can use them for its own authorization rules.

Preferred VM proxy authentication header:

X-Exedev-Authorization: Bearer <token>

The proxy consumes and strips that header before forwarding to the VM.

Other supported forms:

  • Authorization: Bearer <token> is supported but deprecated for new integrations.
  • Basic auth can be used for tools such as git; the username is ignored and the password is the token. This applies to VM proxy access, not /exec.

When authenticated by token, the VM server receives:

  • X-ExeDev-UserID
  • X-ExeDev-Email
  • X-ExeDev-Token-Ctx, if present in the token

Git HTTPS example:

echo "$TOKEN" > ~/.ssh/exe_dev_token
git config credential.helper '!f() { echo "password=$(cat ~/.ssh/exe_dev_token)"; }; f'
git clone https://myvm.exe.xyz/repo.git

Login with exe

Applications served through the exe.dev HTTP proxy can use exe.dev authentication instead of managing their own login system. This is complementary with sharing: public sites can bounce users through the login URL to require an email address, while private sites always carry the authentication headers because access requires the site to have been shared.

When a request is authenticated by exe.dev, the proxy adds:

  • X-ExeDev-UserID: stable exe.dev user identifier.
  • X-ExeDev-Email: authenticated user email address.

For public sites, unauthenticated requests may not include these headers. For private sites, access requires authentication, so the headers are expected.

Special URLs:

  • https://vmname.exe.xyz/__exe.dev/login?redirect={path} redirects the user to log in, then back to {path}.
  • POST https://vmname.exe.xyz/__exe.dev/logout logs the user out, removing the cookie for that domain.

Local development can simulate these headers with a reverse proxy, for example:

mitmdump \
  --mode reverse:http://localhost:8000 \
  --listen-port 3000 \
  --set modify_headers='/~q/X-Exedev-Email/user@example.com' \
  --set modify_headers='/~q/X-Exedev-Userid/usr1234'

Server-side authorization can gate on X-ExeDev-Email directly; the upstream docs include an nginx example that returns 403 unless $http_x_exedev_email matches an allowlist.

VM services must not trust user-controlled copies of these headers when traffic can bypass the exe.dev proxy. Bind private services to localhost or firewall direct VM ports if the header values are part of authorization.

Repository usage

This repository uses the exe.dev HTTPS command API through EXE_DEV_API_KEY for non-interactive VM management:

  • exedev-ctl wraps the exe.dev command surface, including ls, new, rm, restart, rename, tag, comment, stat, cp, resize, share (show, port, set-public, set-private, add, remove, add-link, remove-link, receive-email, access), domain (add, ls, rm), team, invite, whoami, ssh-key, set-region, integrations, billing, shelley, browser, and raw exec.
  • exedev-k8s uses exe.dev VM commands as the infrastructure layer for k3s fleet bootstrapping; against exe.dev itself it only needs ls, new, and rm (node provisioning happens over direct SSH to the VMs).

For local scripts and manual debugging, prefer:

ssh exe.dev <command> --json

For repo automation and services, prefer:

curl -X POST https://exe.dev/exec \
  -H "Authorization: Bearer $EXE_DEV_API_KEY" \
  -d '<command>'

For new automation tokens, grant only the commands that the workflow needs. A minimal exedev-k8s fleet token needs:

{"cmds":["ls","new","rm"],"exp":1798761600}

A broader VM lifecycle token for exedev-ctl workflows typically adds:

{
  "cmds": [
    "ls",
    "new",
    "rm",
    "restart",
    "rename",
    "whoami",
    "share show",
    "share port",
    "share set-public",
    "share set-private",
    "domain ls"
  ],
  "exp": 1798761600
}

Use shorter-lived tokens for CI and long-running automation where replay risk is important.