The API
The BMC serves an HTTP API, and this is its description. It is not written by hand: the daemon emits it, so it describes the code rather than somebody's memory of the code.
The board you are holding serves its own copy at
GET /api/bmc/openapi.json, which is the one to trust if it disagrees with
this page. This page renders the document from a released version, named at
the bottom.
Two spellings of every operation
Section titled “Two spellings of every operation”Upstream's API routes on query parameters: GET /api/bmc?opt=get&type=about.
Everything, including mutations, is a GET. That convention is in people's
scripts and in upstream's own tpi, so it is not going anywhere.
This fork added a second spelling of the same operations — GET /api/bmc/about,
POST /api/bmc/reboot — as a routing table over the same handlers. Same
JSON, same authentication, same code. Not a v2, and not a migration you are
being asked to make.
They differ in exactly two ways, both about the envelope:
legacy ?opt=&type= |
path form | |
|---|---|---|
| success | {"response":[{"result": …}]} |
the bare result, or 204 |
| refusal | the message inside result, with a 200 |
application/problem+json |
The refusal difference is the one that matters. A client reading the legacy
form has to parse a success envelope to discover it failed, and tpi shipped
three formatters that got this wrong.
What the document does and does not describe
Section titled “What the document does and does not describe”Every operation is described: its path, its method, its parameters, which ones are refused if omitted, and both security schemes.
Every read operation describes its response body. The schemas are derived from the Rust types the daemon serialises, so they cannot drift from what it sends, and contract tests hold a realistic response against each of them.
Ten of those operations built their answer inline until v2.15.0, and had no
type to derive from. They have one now — reconstructed from what the handler
already sent, not redesigned. A rename would have broken tpi and the web
interface for nothing.
Three shapes are odd, and the document describes the oddity rather than correcting it:
power,usbandsdcardanswer a one-element array. That is upstream's convention. A schema claiming an object would be a lie that compiles, and a client has to index it either way.sdcard's used-bytes field is calleduse. Upstream's spelling. It is also a Rust keyword, so the daemon renames it on the way out, and a test asserts the name on the wire rather than the one in the source.powerreports strings, not booleans. A rail the daemon cannot read is"Unknown", and a boolean would leave a generated client unable to say so.
The daemon still keeps a list of operations that describe nothing, and a test refuses to let one join it silently. The list is empty, and that is the point of keeping it.
Authentication
Section titled “Authentication”Two schemes, both described in the document. A bearer token from
POST /api/bmc/authenticate, or HTTP basic with the board's root credentials.
Requests from the board itself skip authentication entirely. That is a known fault, not a feature, and since v2.14.0 it at least leaves an audit line saying so.
/metrics is separate: since v2.15.0 it is served on
its own port with no credential at all, and that listener
serves nothing else — so nothing that scrapes it can reach this API.
The operations
Section titled “The operations”Every operation is on its own page, grouped by what it acts on, and every one is in the site's search:
- Every operation — one row per operation, the fastest way in
- The board · The nodes · Firmware
- Storage · Network and time · Cooling and thermals
These pages are generated from the committed document by
scripts/generate-api-pages.py, which just refresh-api runs. They are not
edited by hand, so they cannot drift from the document the daemon emits.