Declare the server to be under maintenance
const url = 'https://api.flotera.com/api/v1/servers/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/maintenance';const options = { method: 'PUT', headers: { cookie: '__Host-erm_session=<__Host-erm_session>', 'Content-Type': 'application/json' }, body: '{"reason":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url https://api.flotera.com/api/v1/servers/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/maintenance \ --header 'Content-Type: application/json' \ --cookie __Host-erm_session=<__Host-erm_session> \ --data '{ "reason": "example" }'The one thing about a server that is not visible from the outside.
Everything else the panel shows about a machine is observed: a rental and a listing come from the marketplace, mining and load come from telemetry, connectivity is presence. Whether the owner has taken the machine out of service for a while is a statement, and it has to be stored.
What this does NOT do. It does not withdraw the offer: that is an action on a live marketplace and stays the owner’s explicit call. It does not interrupt a running rental — on Clore that is impossible at all. It changes nothing about billing: a machine under maintenance is still a managed server for the subscription.
What it does do: the fleet breakdown counts the machine as under maintenance, and the strategy engine stops proposing prices for it.
Repeating the call keeps the original since and only replaces the
reason: declaring maintenance twice does not restart it.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”UUID (v7 for new entities; v4 accepted during migration).
Header Parameters
Section titled “Header Parameters”Idempotency key, 1–128 ASCII, unique per (tenant_id, operation, key) for at least 24 hours. Retrying with the same body replays the stored response; a different body returns 409 idempotency_conflict.
Request Body
Section titled “Request Body”Reason shown next to the badge and recorded with the declaration. A declaration without a reason is legitimate: «I know why» is an answer.
object
Examplegenerated
{ "reason": "example"}Responses
Section titled “Responses”Declared; the detail carries the window.
Server detail — PG config merged with the latest telemetry read model.
object
UUID (v7 for new entities; v4 accepted during migration).
Null until an agent registers on the server.
Historical field. The server FSM it was meant to carry has no writer anywhere in the system, so this is always new; read maintenance for what the owner declared, and the marketplace link for a rental or a listing. Kept in the response so existing clients do not break.
The owner’s declaration that the machine is out of service. Absent on a machine in service — a machine is not «not under maintenance», it just works, and an object of nulls would say otherwise.
object
When it was declared; repeating the declaration keeps it.
Presence read model over the agent’s WebSocket session (the channel commands travel on): suspect after 60 s without a heartbeat, offline after 300 s. HTTPS-only liveness (agent hello) never makes a server online.
Active marketplace assignment; null when unassigned.
Decimal string or null when unknown.
Last WebSocket heartbeat of the agent session — the same source presence is derived from, so the two never disagree. Null until the command channel comes up at least once; an agent that only reaches the core over HTTPS (hello) does not move this field.
Decimal value serialized as a string, never a JSON number.
Average GPU utilization percentage over the server’s GPUs.
key or key:value tags; empty until any tag is set.
One per-GPU vitals sample for the fleet Temp/Fan bars, ordered by GPU index.
object
UUID (v7 for new entities; v4 accepted during migration).
object
UUID (v7 for new entities; v4 accepted during migration).
Memory technology (GDDR6, GDDR6X, HBM2…) as the agent read it from the card. Null until an agent that reports it delivers a sample — the value differs between production batches of one model, so it is never inferred from the model name.
Memory chip manufacturer (Samsung, Hynix, Micron…).
Board brand (ASUS, Palit, MSI…), resolved server-side from the raw PCI subsystem vendor id the agent reports. Null for agents that predate the field and for ids the dictionary does not know.
Latest per-GPU telemetry sample (Redis latest read model).
object
RFC 3339 UTC with microsecond precision, or null.
Agent-reported fan mode: auto | managed | manual.
Power limit currently in force on the card.
Factory power limit of the card. Shown next to the one in force so that a single number cannot be mistaken for the stock value.
Lowest fan duty the card accepts. Zero is usually unreachable: zero-RPM sits below the adjustable range and the card enters it on its own rather than on command.
Highest fan duty the card accepts.
Lowest power limit the card accepts. Asked of the device rather than taken from a model table: cards of the same model with different vbios differ.
Highest power limit the card accepts. Together with the minimum it is the range set_power_limit is validated against, so a client can offer only values the hardware will take.
object
UUID (v7 for new entities; v4 accepted during migration).
rented / listed / expired. Expired means the fixed listing window has passed: the platform may still report the machine as listed while it is already absent from search results.
Marketplace-specific price structure.
object
End of the fixed listing window. Absent for rolling-window offers (the platform slides their end date itself) and for marketplaces without a listing deadline.
Rolling-window length in seconds when the offer uses one; the platform keeps moving the end date, so such an offer never expires on its own.
Latest host sample; null fields until the sensor reports. Sizes are binary MB (1 MB = 1048576 bytes) to match ram_used_mb; rates are kB/s with a decimal kilobyte (1 kB/s = 1000 bytes/s), the unit the panel converts to Mbit/s.
object
RFC 3339 UTC with microsecond precision, or null.
Total physical RAM. Same quantity as inventory.ram_mb, but it rides every sample instead of waiting for the first hello — the fresher of the two, and the only one available before hello.
Capacity of the volumes the agent tracks, summed.
Receive rate over the interval between the two most recent samples, derived from the agent’s monotonic byte counters. Null whenever no honest delta exists: before a second sample arrives, and right after a host reboot, where the counter restarted from zero and the difference would read as a drop, not a rate.
Transmit rate; derived exactly like net_rx_kbs.
Accounted host power draw in watts under the owner’s power source (settings.power_source): the GPU sum plus the enabled additions, as summed by the agent. It already INCLUDES the cards — never add it to the per-GPU sum. Null until an agent aware of the setting reports, or when the enabled components produced no reading.
Static hardware inventory reported at agent hello and stored verbatim. Nothing here is required and every leaf is explicitly nullable: an absent key and an explicit null say the same thing — the agent looked and could not tell. Sizes follow the vendor’s own labelling (decimal GB for drives), unlike the binary MB of HostLive.
object
Primary CPU package; cores/threads count the whole host.
object
Total physical RAM in binary MB, frozen at hello. HostLive carries the same number per sample as ram_total_mb.
Block devices enumerated at hello, in kernel device order.
object
Kernel device name without /dev/ — nvme0n1, sda.
Capacity in decimal GB (1e9 bytes), as the drive is labelled.
Mount points of the volumes that live on THIS drive — ["/", "/boot/efi"]. The panel uses them to put a usage bar under
the drive it belongs to: usage arrives with telemetry and
knows only its own tree, while which drive holds that tree is
visible here. Guessing by matching capacity is not an option —
two identical drives give two equally plausible answers.
An empty array is an answer: the drive is there and nothing on it is mounted (a fresh drive before partitioning, or a filesystem this kernel cannot mount). Absent means the agent predates the field.
Distribution and release — Ubuntu 22.04.4 LTS.
Kernel release, uname -r.
NVIDIA driver version — 550.90.07.
CUDA version the driver reports — 12.4.
Uplink interface — the one carrying the default route.
object
Negotiated link speed, not measured throughput.
What the agent says about itself, as opposed to inventory, which describes the machine: the mode it runs in (native/emulator), the privileges it was granted (full/readonly), which module is currently producing GPU telemetry, and the full module registry with a reason attached to every unavailable one. The same machine with the same hardware yields a different report depending on whether the owner granted root at install time.
Shape follows HardwareReport in agent-v1.yaml. The value is passed through unaltered — its shape was checked when the hello was accepted, but its vocabulary is deliberately open, because a value this control plane does not recognise means an agent newer than it, and refusing one would stop the whole fleet from checking in exactly while it is being upgraded.
null means never reported. Clients must not collapse that with an empty module list: the first is fixed by upgrading the agent, the second by restarting its hardware layer.
Which command types this agent can execute on this host, including the ones it cannot, each carrying a reason. Shape follows ToolReport in agent-v1.yaml.
A tool is not a second kind of entity next to commands; it is a registered command type plus the agent’s statement about executing it here and now. Clients render actions from this list and explain the disabled ones from the same field — an absent button and a disabled button with a reason are different messages to an operator, and only the second one tells them whether to grant privileges, replace hardware, or upgrade.
null means never reported; [] means the agent answered and can execute nothing.
object
Which rental platforms the owner keeps on this server, keyed by platform name. Always present: {} is a knowable state (“none added”), not missing information, which is why this field has no null.
Keyed rather than a list, for two reasons that both showed up before the first line of UI. A list admits two entries for one platform and the bug surfaces as a duplicated tile; a key cannot. And a partial write addresses {vast}, a path that stays valid, where a list index shifts the moment somebody removes a platform — two operators adding platforms at once would lose one of the two writes.
Order is not stored because order is presentation: the host system first, then by added_at, which each entry carries.
The host system is deliberately absent here. It is not added and cannot be removed, so it has no intent to record; it appears only in platform_report, where having it in the same shape as the platforms is what lets one renderer draw both.
object
One platform on one server. Deliberately thin: everything observed about the platform — is its agent installed, which version, what machine id — belongs to platform_report, because it is measured rather than decided, and re-measuring must never be able to damage what the owner decided.
One platform on one server. Deliberately thin: everything observed about the platform — is its agent installed, which version, what machine id — belongs to platform_report, because it is measured rather than decided, and re-measuring must never be able to damage what the owner decided.
Result of the last platform check, for the host system and for every platform on this server. Shape follows ServerPlatformReport, kept an open object here for the same reason hardware_report is: a newer agent measures more, and a control plane that rejected the extra field would break the fleet exactly while it upgrades.
null means no check has ever run — not “nothing found”. Half of what the platforms require cannot be measured by anything today, so a client that renders an absent report as all-clear states as fact what nobody has looked at. The two states are stored apart and must stay apart in the UI.
Kept in a column of its own, separate from platforms: an observation is reproducible by running the check again, while the intent behind it is not reproducible at all, and the two do not belong in one cell that a frequent automatic writer rewrites.
What the last network measurement saw of this host FROM THE OUTSIDE — the observed address, the dial-back outcome per port, the round trip, and throughput when it was asked for. Shape follows ServerNetworkReport, kept an open object here for the same reason the two reports beside it are.
null means the network has never been measured. That is a different statement from “no public address”: a machine nobody looked at and a machine behind carrier NAT are a good host and an unusable one, and a client that renders the first as the second turns silence into a verdict.
A column of its own, not a field inside platform_report: two different commands write them, and one cell shared by two independent writers can only be updated read-modify-write, which loses half of it silently when the two coincide. The truths also age differently — a host fact goes stale when the owner changes the machine, a network fact when the ISP changes something, and one checked_at for both would let a fresh filesystem check silently rejuvenate a year-old bandwidth figure.
Applied per-server config (registry.servers settings); fields appear once applied.
object
Power accounting source: which components make up the host power
reported in telemetry and billed as electricity. gpus (the
default when absent) — GPU cards only; gpus_plus_fixed — GPU
cards plus power_fixed_w; meter — an external wall-socket
wattmeter (Tasmota HTTP API) on the host’s LAN, paired with
power_meter_host. Under meter the wall reading is the host
draw verbatim; an unreachable meter reports the sample as
unmeasured, never zero. Agents older than the first meter-aware
version keep reporting GPU cards only: the core does not send
them the setting.
Fixed platform draw in watts (motherboard, CPU, drives, fans);
paired with the gpus_plus_fixed power source.
Wattmeter address on the host’s LAN as host[:port] — no
scheme, no path; paired with the meter power source. The
agent builds the Tasmota status URL itself and never fetches an
owner-supplied URL verbatim.
Display label of the meter — the Tasmota DeviceName captured by
the panel when the address was last checked or picked from
discovery (server.probe_meters). Purely informational: the
agent never reads it, and it refreshes on the next check rather
than tracking renames live.
Latest agent build offered by the control plane; null when none newer.
True while the tenant is billing-locked; live telemetry is blanked.
Monotonic resource version used for ETag/If-Match.
RFC 3339 UTC with microsecond precision.
RFC 3339 UTC with microsecond precision, or null.
Example
{ "presence": "online", "revenue_today_usd": "12.340000", "platforms": { "vast": { "added_at": "2026-07-25T10:15:30.123456Z" }, "clore": { "added_at": "2026-07-25T10:15:30.123456Z" } }, "created_at": "2026-07-25T10:15:30.123456Z"}Missing/invalid credentials (code=unauthorized).
RFC 9457 problem document with a stable machine code.
object
Stable machine-readable error code (03 §2.4).
UUID (v7 for new entities; v4 accepted during migration).
object
JSON Pointer to the offending field.
Example
{ "type": "https://ermeon.com/problems/validation", "code": "unauthorized"}Authenticated but not permitted. code=forbidden — role/scope mismatch; code=feature_not_entitled — the plan does not include the capability; code=account_frozen — the account is frozen and this operation is declared x-ermeon-frozen: deny. The three are deliberately distinct: only the last one is fixed by a top-up (13 §5.6).
RFC 9457 problem document with a stable machine code.
object
Stable machine-readable error code (03 §2.4).
UUID (v7 for new entities; v4 accepted during migration).
object
JSON Pointer to the offending field.
Example
{ "type": "https://ermeon.com/problems/validation", "code": "unauthorized"}Resource does not exist in this tenant. Foreign identifiers also return 404 (anti-enumeration).
RFC 9457 problem document with a stable machine code.
object
Stable machine-readable error code (03 §2.4).
UUID (v7 for new entities; v4 accepted during migration).
object
JSON Pointer to the offending field.
Example
{ "type": "https://ermeon.com/problems/validation", "code": "unauthorized"}Request failed validation (code=validation_failed), with per-field errors.
RFC 9457 problem document with a stable machine code.
object
Stable machine-readable error code (03 §2.4).
UUID (v7 for new entities; v4 accepted during migration).
object
JSON Pointer to the offending field.
Example
{ "type": "https://ermeon.com/problems/validation", "code": "unauthorized"}A dependency the endpoint needs is not configured or is temporarily unavailable (code=unavailable). The rest of the API keeps working — an absent external integration must not take the service down.
RFC 9457 problem document with a stable machine code.
object
Stable machine-readable error code (03 §2.4).
UUID (v7 for new entities; v4 accepted during migration).
object
JSON Pointer to the offending field.
Example
{ "type": "https://ermeon.com/problems/validation", "code": "unauthorized"}