Skip to main content
The boxd CLI, SSH server, and SDKs are all clients of one thing: the public gRPC API at boxd.sh:9443. If your language doesn’t have a boxd SDK yet, generate one from the proto file and talk to it directly.

Endpoint

boxd.sh:9443
  • Transport: HTTP/2 cleartext (h2c). No TLS on this port β€” auth is short-lived JWTs.
  • Reflection: gRPC server reflection is enabled, so tools like grpcurl work without the proto file.
  • Service: boxd.api.v1.BoxdApi

The proto

Copy the full service definition into a local api.proto, then generate stubs with protoc, buf, grpc_tools, or @grpc/proto-loader. The proto is proto3 with no external imports β€” generation is one command. You don’t strictly need the file: since server reflection is on, grpcurl and buf curl work directly against the endpoint, and grpcurl -plaintext boxd.sh:9443 describe boxd.api.v1.BoxdApi dumps the schema on demand.

Authentication

Two-step: long-lived API key β†’ short-lived JWT β†’ bearer token on every gRPC call.

1. Create an API key

API keys are issued from the boxd console. Sign in at boxd.sh, open the API keys page, and create one. The raw key is shown once β€” copy it immediately. Format: bxd_ followed by ~40 base62 characters. You can also create them via the CLI once you’re logged in:
boxd login                              # GitHub OAuth
boxd api-key create --name=my-app

2. Exchange for a JWT

Send the API key to the exchange endpoint over HTTPS:
curl -X POST https://boxd.sh/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"api_key":"bxd_..."}'
{
  "token": "eyJhbGciOi...",
  "expires_at": 1735689600,
  "user_id": "gh-username"
}
The JWT is short-lived (default ~1 hour). Re-exchange before expiry. Rate-limited per source IP.

3. Send it on every gRPC call

authorization: Bearer eyJhbGciOi...
Standard gRPC metadata. Most generated clients expose this as a per-call interceptor or call option.

Hello world

Easiest way to verify auth and reachability β€” no proto file needed (server reflection is on).
# Set your JWT
export BOXD_JWT="$(curl -s -X POST https://boxd.sh/api/v1/auth/token \
  -H 'Content-Type: application/json' \
  -d '{"api_key":"bxd_..."}' | jq -r .token)"

# Whoami
grpcurl -plaintext \
  -H "authorization: Bearer $BOXD_JWT" \
  boxd.sh:9443 boxd.api.v1.BoxdApi/Whoami

# Create a VM
grpcurl -plaintext \
  -H "authorization: Bearer $BOXD_JWT" \
  -d '{"name": "hello-grpc"}' \
  boxd.sh:9443 boxd.api.v1.BoxdApi/CreateVm

# List VMs
grpcurl -plaintext \
  -H "authorization: Bearer $BOXD_JWT" \
  boxd.sh:9443 boxd.api.v1.BoxdApi/ListVms
Install: brew install grpcurl or github.com/fullstorydev/grpcurl.

Errors

Standard gRPC status codes. The most common ones you’ll hit:
CodeWhen
UNAUTHENTICATEDMissing/malformed/expired JWT, or authorization metadata not set
NOT_FOUNDVM, disk, template, or domain doesn’t exist
RESOURCE_EXHAUSTEDPer-user VM quota reached
INVALID_ARGUMENTBad request shape (e.g. invalid VM name, conflicting fields)
INTERNALServer-side error
The error message in Status.message() is human-readable and safe to surface to users.

Streaming RPCs

Two RPCs use streams:
  • StreamLogs β€” server-streaming, emits LogChunk messages as the VM produces output. Set follow=true to keep the stream open after current logs flush.
  • Exec β€” bidirectional. First message must contain vm_id and command; subsequent client messages with stdin=true pipe stdin, or window_change=true with cols/rows resize a PTY. Server messages carry data with is_stderr set to true for stderr chunks and false (default) for stdout. PTY-mode execs merge stderr into stdout at the kernel, so is_stderr is only set for non-PTY execs. Final server message has exit_code set. Clients close their send half of the bidi stream to signal stdin EOF to the subprocess (the proxy translates this to CHANNEL_EOF on the underlying SSH channel).

What’s next

https://mintcdn.com/azin/Ax1V0serIwQf0x_2/images/icons/command.svg?fit=max&auto=format&n=Ax1V0serIwQf0x_2&q=85&s=6c33d9e29e4e937c0950311233ec5659

CLI

Same API, no codegen β€” useful for shell scripting and one-offs.
https://mintcdn.com/azin/Ax1V0serIwQf0x_2/images/icons/server-square.svg?fit=max&auto=format&n=Ax1V0serIwQf0x_2&q=85&s=1bbbc4c3c59a2e4c73bca3d24a58fb2c

Primitives: Machines

Concepts behind CreateVm / ForkVm / SuspendVm.