Skip to content

API

The API is Bitsmith’s stable HTTP surface: REST endpoints for the resources the server manages: virtual machines, LXC containers, apps, folders, connected storage, the reverse proxy, and sandboxes. MCP exposes the same operations to agent clients; the API complements it for integrations that are not MCP clients: scripts, server-side services, and anything that can send a bearer token. Both transports use the same agent tokens, the same scopes, and the same activity log, so a token you create works on both with no extra setup.

The API lives under /api/v1/ and authenticates with Authorization: Bearer <token>, where the token is one you created on the Access tokens page (System, Agent access).

Resources follow standard REST conventions:

  • GET /api/v1/vms lists the collection, POST /api/v1/vms creates one.
  • GET /api/v1/vms/12 reads an item by its path parameter; PATCH updates, DELETE removes.
  • Actions live on the item as sub-paths: POST /api/v1/vms/12/start, POST /api/v1/vms/12/exec, POST /api/v1/vms/12/template.
  • Every domain has the same shape: /api/v1/lxc, /api/v1/apps, /api/v1/folders, /api/v1/locations, /api/v1/proxy, /api/v1/sandboxes, plus /api/v1/system, /api/v1/activity, /api/v1/peers, and /api/v1/tasks.

Path parameters are part of the URL and always named id or the natural sub-resource name (image_id, sub_path). A path parameter fills the operation’s argument of the same name; for example, the {id} in /api/v1/vms/{id} is the VM ID. The rest of an operation’s arguments go in the JSON body for POST, PATCH, and PUT, and in the query string for GET and DELETE. peer_id works in either place, wherever the operation accepts it.

The full listing for this release (every endpoint, its method and path, its summary, its scope, and the JSON schema of its arguments) is generated in the API reference. The catalog is defined by your server build, so GET /api/v1/catalog remains the authoritative source for what a given server can do: read it when in doubt.

The plain-HTTP listener answers these paths directly rather than redirecting to HTTPS, for the same reason it does for /mcp: plain curl and integration code cannot click through a self-signed certificate.

List the virtual machines:

Terminal window
curl -s http://<your-server>/api/v1/vms -H "Authorization: Bearer $TOKEN"

Create a folder:

Terminal window
curl -s -X POST http://<your-server>/api/v1/folders \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"storage_id": "tank", "name": "agent-inbox"}'

Start VM 12:

Terminal window
curl -s -X POST http://<your-server>/api/v1/vms/12/start \
-H "Authorization: Bearer $TOKEN"

Read the live catalog:

Terminal window
curl -s http://<your-server>/api/v1/catalog -H "Authorization: Bearer $TOKEN"

Operations that act on a single server accept an optional peer_id argument, in the body or the query string, that routes the call to a paired server. The peer runs it with your token’s scopes forwarded across; leave the argument out to target the server you called.

Every error comes back as {"error": "..."} with a status code:

StatusMeaning
400The body is not a JSON object, or an argument does not fit the schema.
401No token, or a token that does not match.
403The token lacks the scope the endpoint needs.
404The path is not an endpoint this server offers, or the resource it names does not exist.
405Wrong method for the path; the Allow header lists the valid ones.
409The resource’s state blocks the call, such as changing a running VM.
413The request body is over 1 MiB.
500The call failed in a way that has no specific code; the error text names what happened.
502The call was routed to a paired server that failed to run it.
503A host dependency such as the VM runtime is unavailable.

Every mutating call writes one row to the Activity log, attributed to the token’s name, exactly as an MCP call would. The row’s metadata records which transport it arrived on: mcp, api, or cluster (the peer that ran a forwarded call). Read-only calls are not recorded.