Zaroz
Zaroz Cloud Kernel Open API

Get Service Instance FiveM Live Info

GET
/api/v2/service-instances/{id}/fivem/live

A FiveM service's live info: hostname, gametype, map, players connected and the slot count, and the player list (id, name, ping only; never an IP or identifier). Read server-side from the FXServer's own dynamic.json and players.json on the service's primary allocation. Always answers 200; status carries every reason there is nothing to show (not_configured when the product does not offer the panel, no_address, offline, parse_error, error) and the panel renders each as a state. ^N colour codes are stripped. 404 for an instance with no external access, or belonging to somebody else.

Get Service Instance FiveM Live Info › path Parameters

id
​string · uuid · required · style: simple

Get Service Instance FiveM Live Info › Responses

The live info, or a degraded status when it could not be read

​FivemPlayerResponse[] · required

Empty unless status is ok.

​FivemLiveStatus · required
​

Present only when status is ok.


Get Service Instance Minecraft Players

GET
/api/v2/service-instances/{id}/players

The Minecraft player roster: who is online, who is an operator, and who is banned, fused server-side from RCON list and the two files a Minecraft server itself keeps (ops.json, banned-players.json) -- never a client-side join of three payloads. Always answers 200; status carries every reason the roster could not be produced (not_configured for a service that is not Minecraft or predates the RCON password this needs, server_offline, auth_failed, unreachable, timeout, protocol_error, parse_error), and the panel should render each as a state rather than an error banner. ops_unavailable and banned_unavailable degrade independently: a roster missing its ban list is still a roster, one missing its online list is not (that case is the status field instead). ?include=gamemode,position opts the online players into their current game mode and their dimension and coordinates (one RCON round trip per player each, so the slow path stays opt-in); a player the server will not answer for simply has the field absent, and an unknown include value is a 400. 404 for an instance with no console at all, or belonging to somebody else.

Get Service Instance Minecraft Players › path Parameters

id
​string · uuid · required · style: simple

Get Service Instance Minecraft Players › query Parameters

include
​string | null · style: form

Comma-separated opt-in enrichments of the online players: gamemode (each player's current game mode) and position (dimension and coordinates). Each costs one RCON round trip per online player, so ask only for what the panel shows.

Comma-separated opt-in enrichments of the online players: gamemode (each player's current game mode) and position (dimension and coordinates). Each costs one RCON round trip per online player, so ask only for what the panel shows.

Get Service Instance Minecraft Players › Responses

The fused roster, or a degraded status when it could not be read

The roster: online players, operators and bans, fused server-side (`fuse_snapshot`) exactly as `ZC-0463-game-surfaces-design.md` §1's "1." describes -- never a client-side join of three payloads.
​BannedPlayerResponse[] · required

Empty unless status is ok.

banned_unavailable
​boolean · required

Same meaning as ops_unavailable, for banned-players.json.

​OnlinePlayerResponse[] · required

Empty unless status is ok.

​OperatorPlayerResponse[] · required

Empty unless status is ok.

ops_unavailable
​boolean · required

True when ops.json could not be read or parsed. ops is then empty, but that does not mean nobody is an operator -- it means this answer cannot say.

partial_list_format
​boolean · required

True when /list's reply did not match the vanilla format and had to be parsed permissively (parser::parse_list's tier 2). The roster is still usable; this is a hint that the counts may be approximate on a heavily modded server.

​MinecraftPlayersStatus · required

Every outcome a read or a write can answer with, folded into one status so a client renders a match rather than branching on HTTP status codes that are all 200. Ok is the only variant the roster fields or the action actually succeeding are meaningful under.

max_players
​integer | null · uint32 · min: 0

Execute Service Instance Minecraft Player Action

POST
/api/v2/service-instances/{id}/players/actions

Runs one of the nine Minecraft player-management verbs (kick, ban, pardon, op, deop, gamemode, whisper, give, broadcast) over RCON. Every field is validated before anything reaches the server -- a malformed name, item id or message is a 400 naming which -- and a request that passes validation still answers 200 with a status field for every way running it could fail (the server is offline, RCON auth failed, the command timed out, or the server's own reply indicates the verb was not understood, which unsupported_by_server covers separately from every other status). Gated the same as attaching to this workload's console: an organization Owner or Admin, or the personal organization's owner. Every successful call is audited under a per-verb action name; message bodies (a kick or ban reason, a whisper, a broadcast) are never written to the audit log verbatim, only their length or whether one was given.

Execute Service Instance Minecraft Player Action › path Parameters

id
​string · uuid · required · style: simple

Execute Service Instance Minecraft Player Action › Request Body

oneOf
Exactly one variant must match.

Decision Table

VariantMatching Criteria
type = object · requires: kind, name
type = object · requires: kind, name
type = object · requires: kind, name
type = object · requires: kind, name
type = object · requires: kind, name
type = object · requires: kind, name, mode
type = object · requires: kind, name, message
type = object · requires: kind, name, item +1 more
type = object · requires: kind, message
Properties for Variant 1:
kind
​string · const · required
Const value: kick
name
​string · required
reason
​string | null
Default: null

Execute Service Instance Minecraft Player Action › Responses

The verb's outcome, as a status

The outcome of one action.
​MinecraftPlayersStatus · required

Every outcome a read or a write can answer with, folded into one status so a client renders a match rather than branching on HTTP status codes that are all 200. Ok is the only variant the roster fields or the action actually succeeding are meaningful under.


List Subscription Resources

GET
/api/v2/subscriptions/{id}/resources

Lists the resources provisioned for one subscription in any organization the caller may see (design doc §44.2). An empty list is normal -- a subscription may have zero, one, or many resources (design doc §8.1); at most one resource is ever marked is_declared_primary, and none may be. When primary_role_is_inconsistent is true, two resources both satisfied the primary rule -- a data fault, never a legitimate state -- so no resource is marked and a consumer should surface the inconsistency rather than render it as an absent primary.

List Subscription Resources › path Parameters

id
​string · uuid · required · style: simple

List Subscription Resources › Responses

Resources

`GET /api/v2/console/subscriptions/{id}/resources`. Not paginated, unlike `ListSubscriptionsResponse` -- one subscription's resource set is small and bounded (design doc `§9.1`: "the modal shape today is already 2-3 Deployments per order"), the same reasoning `kernel_http_v2_catalog::contracts::products::ListProductPlansResponse` already applies to one product's plan list. **`data` is normal when empty.** Design doc `§8.1`: a `Subscription` has zero, one, or many `Resource`s -- a per-seat license (Zac, ZarozScanner) provisions no resource at all. Validation case `V2` was un-ignored specifically to establish that this is not an error state; see this crate's report for where that is exercised.
​ResourceResponse[] · required
primary_role_is_inconsistent
​boolean · required

true when two live resources both satisfy the primary rule, which A2-S9b made a hard error because it is never a legitimate state (design doc §9.1).

When set, every is_declared_primary in data is false -- the resolver refuses to guess between them -- and a consumer should say so rather than render "no main resource", which is indistinguishable from a subscription that legitimately has none.

It is a field rather than an error because this is a read-only display surface and failing the whole response helps nobody. It is a field rather than a log line because a silent degrade would make the screen most likely to reveal the corruption the screen that hides it (design doc §50).

​object · required

The running service these resources belong to, carrying the name and slug the customer refers to it by. Included here rather than fetched separately because this read already resolves the instance to find the resources at all.


List Service Instance Resources

GET
/api/v2/service-instances/{id}/resources

The live resources of one service (id, kind, role, status, hidden, and whether it is the product's declared primary): the ids the console, files, logs and metrics routes are addressed by. Open to everyone who may View the service: its organization's members and a per-service share holder, whose answer carries nothing about the subscription or its billing. 404 for anyone else.

List Service Instance Resources › path Parameters

id
​string · uuid · required · style: simple

List Service Instance Resources › Responses

The service's resources

`GET /api/v2/service-instances/{id}/resources`: the service's live resources, for owners (organization doors) and per-service share holders alike.
primary_role_is_inconsistent
​boolean · required

true when two live resources both satisfied the primary rule (a data fault); then no resource is marked is_declared_primary.


Reinstall VPS

POST
/api/v2/service-instances/{id}/resources/{resource_id}/reinstall

Reinstalls a VPS onto the operating system osImage (an id from GET /api/v2/catalog/products/{id}/operating-systems; the image already installed is allowed). Erases all data on the disk and cannot be undone: confirm must be true, and is required rather than defaulted so a request that lost it is a 400 and not a wipe.

Only a virtual machine of a VPS service can be reinstalled; any other resource is a 422. An image that is disabled, or whose minimum CPU, memory or storage this VPS does not meet, is a 400. So is an image whose monthly fee differs from the installed one: a reinstall cannot change what the subscription costs, so such an image needs a new order. The service's subscription must be serviceable, as for reprovisioning.

Answers 202 with an operation id. The rebuild runs on the durable reprovision queue, waits its turn behind any backup, restore or deployment holding this service, and survives a kernel restart. When it finishes the machine is down with its old credentials cleared: answer the service's vm_access setup step with a new administrator account and that write boots the fresh install. Public endpoints survive. Requires the same access as changing the service (orders.manage for an API token).

Reinstall VPS › path Parameters

id
​string · uuid · required · style: simple
resource_id
​string · uuid · required · style: simple

Reinstall VPS › Request Body

Body of the VPS reinstall route. Both fields are required and neither has a default: this destroys every byte on the machine's disk, so a request that lost a field in transit must be a 400 and never a wipe. `deny_unknown_fields` for the same reason: a client that misspells `confirm` is refused rather than defaulted.
confirm
​boolean · required

Must be true. Reinstalling erases all data on the disk and cannot be undone; the client is expected to have shown that to the person before sending it.

os_image
​string · uuid · required

The operating system to install: the id of one entry of GET /api/v2/catalog/products/{id}/operating-systems. May be the image already installed.

Reinstall VPS › Responses

The queued rebuild's operation id, for polling its status

What queuing a reinstall did.
operation_id
​string · uuid · required

The queued rebuild. Poll GET /api/v2/service-instances/{id}/operations/{operation_id}.

os_image
​string · uuid · required

The operating system the machine will be rebuilt with.

resource_id
​string · uuid · required
service_instance_id
​string · uuid · required

List Service Instance Backups

GET
/api/v2/service-instances/{id}/resources/{resource_id}/backups

Every on-demand backup of this volume, newest first. maxBackups is the ceiling a create is refused against, published here so a panel never holds it as a literal. These are the customer's own snapshots; the platform's disaster-recovery backups run on a separate mechanism and never appear here. 404 for a resource that is not this volume, for a volume belonging to somebody else, and for a service whose product has no storage, which are deliberately the same answer.

List Service Instance Backups › path Parameters

resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

List Service Instance Backups › Responses

This volume's backups, newest first

Every backup of one volume, newest first (`BackupRepository::find_by_provision`'s own order).
​BackupResponse[] · required
max_backups
​integer · uint32 · min: 0 · required

The ceiling POST .../backups is refused against, published here so a panel never holds it as a literal.


Create Service Instance Backup

POST
/api/v2/service-instances/{id}/resources/{resource_id}/backups

Starts a snapshot backup of this volume. Runs in the background: the row this creates appears in the listing immediately with status: "creating" and becomes restorable once it reaches status: "ready". Refused with a quota error once this volume already holds maxBackups, and with a conflict while another backup or restore is already in progress for this volume. Refused entirely on a cluster that does not support volume snapshots. 404 for a resource that is not this volume and for one belonging to somebody else.

Create Service Instance Backup › path Parameters

resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

Create Service Instance Backup › Request Body

name
​string | null

Optional label. Kernel fills in a timestamped default ("Backup 2026-09-10 14:35") when this is absent, null, or blank.

Default: null

Create Service Instance Backup › Responses

Backup started; poll the listing for its progress

No data returned

Delete Service Instance Backup

DELETE
/api/v2/service-instances/{id}/resources/{resource_id}/backups/{backup_id}

Deletes one backup and its underlying snapshot. Refused while the backup is still creating or restoring -- delete it once it settles into ready or failed. Returns no body, because there is no row left to return; read the remaining set from the listing. 404 for a backup belonging to another instance and for one that does not exist, deliberately the same answer.

Delete Service Instance Backup › path Parameters

backup_id
​string · uuid · required · style: simple
resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

Delete Service Instance Backup › Responses

Backup deleted

No data returned

Restore Service Instance Backup

POST
/api/v2/service-instances/{id}/resources/{resource_id}/backups/{backup_id}/restore

Rolls this volume back to a previous backup. Irreversible: the workloads mounting it are stopped, its data is reverted to the snapshot, then they restart -- every change made since the backup was taken is lost. The backup must be status: "ready". Runs in the background across many reconciler ticks; poll the listing for restorePhase. Refused with a conflict while another backup or restore is already in progress for this volume. 404 for a backup belonging to another instance and for one that does not exist, deliberately the same answer.

Restore Service Instance Backup › path Parameters

backup_id
​string · uuid · required · style: simple
resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

Restore Service Instance Backup › Responses

Restore started

No data returned

Create Resource Command Console Session Ticket

POST
/api/v2/service-instances/{id}/resources/{resource_id}/command-console/session-ticket

Mints a short-lived signed URL for attaching to one workload's own console, through the cluster's edge gateway.

This is not a shell, and a client must not present it as one. The service behind it opens a PTY around the workload's own entrypoint and fans that single process's output out to every viewer; typing sends bytes to that process's stdin. There is no shell to drop to, no second session to open, and no command available beyond the ones the workload's own console implements. The separate Pty capability, which would be a real shell, has no backend on this platform and therefore no route.

Writes nothing. It is a POST because it produces a credential and because the audit entry is written before the credential is handed over. Every call returns a different single-purpose URL, and a GET that does that is one a browser, a proxy or a history entry will cache and replay.

The session is shared, not exclusive. One process, one PTY, one output stream: two people attached see the same bytes, including each other's typing, and both can type. That is deliberate and is the opposite of Framebuffer, which takes a lock because two pointers on one screen is a bug.

Attaching is the backlog. The bridge replays its own rolling scrollback buffer down the same socket on attach, so there is no separate history request and no cursor. When the buffer has been truncated the replay is prefixed with an ANSI soft reset, so the stream is ANSI and a client either interprets it or strips it; it must not render it as literal text.

There is no container parameter and there cannot be one. The bridge is per pod, not per container: it binds a fixed port, every container in the pod shares one network namespace, and it wraps the pod's entrypoint. This is the sharpest difference from createResourceLogStreamTicket, whose ticket must name exactly one container.

expires_at is a redemption deadline, not a session deadline. The gateway checks the ticket once, at the WebSocket upgrade, and an attached session then runs until one side disconnects. Redeem it immediately; do not re-mint to stay connected.

Gated on the permission to change the service, not the permission to see it: an ordinary organization member who can read a service cannot type into its console. 404 when the instance has no command console, when the named workload is not the one that has it, or when its cluster has no edge gateway configured.

Create Resource Command Console Session Ticket › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose console is being attached to.

The workload within it whose console is being attached to.

id
​string · uuid · required · style: simple

Create Resource Command Console Session Ticket › Responses

A signed, short-lived URL for attaching to one workload's console

`POST /api/v2/console/service-instances/{id}/resources/{resource_id}/command-console/session-ticket`.
expires_at
​string · date-time · required

When the gateway stops accepting this ticket.

This is a redemption deadline, not a session deadline. cluster-agent checks exp once, when the socket is upgraded (gateway/edge_token.rs:41, called from gateway/terminal.rs:35); an attached session then runs until one side disconnects. So a client redeems the ticket immediately and never re-mints to stay connected: it mints again only to attach again.

url
​string · required

The gateway URL to open a WebSocket against, carrying the signed ticket in its query string.

Binary frames both ways, and no subprotocol: cluster-agent's /terminal upgrade negotiates none (cluster-agent/src/gateway/mod.rs:88), unlike its /vnc and /ssh upgrades. Anything that is not a binary frame is dropped by the gateway rather than refused (gateway/terminal.rs:107), so there is no control channel to speak into.


Create Resource Exec Pty Session Ticket

POST
/api/v2/service-instances/{id}/resources/{resource_id}/exec/session-ticket

Mints a short-lived, single-use signed URL for opening a NEW interactive shell (bash, falling back to sh) inside one container of one workload, through the cluster's edge gateway.

This is not the command console. createResourceCommandConsoleSessionTicket types into the workload's own entrypoint; this starts a separate shell beside it, the way kubectl exec -it does. Browser SSH on a virtual machine is a third, separate capability.

Open the URL as a WebSocket with the zaroz-pty-v1 subprotocol and append &columns=<1..=500>&rows=<1..=200>. Binary frames carry terminal bytes both ways; a client text frame {"type":"resize","columns":100,"rows":40} resizes (out of range ends the session); the server sends {"type":"exit","code":n} when the shell exits and {"type":"session_end","reason":...} before any close it initiates, after which the client must not retry the same URL.

Single use. expires_at is a redemption deadline, about ten seconds. Redeem it immediately; a reconnect mints a new one. The open session ends on its own after an idle period or a maximum length set by the gateway.

Writes nothing but an audit entry, written before the credential is handed over; it is a POST because it produces a credential.

container is optional and must be a container the pod runs; omitted, it is the workload's configured one, else its primary. Which workloads offer a shell is data on the workload: a product can switch it off. Gated on the permission to change the service, like the command console. 404 when the instance or workload offers no shell, when it has no running pod, or when its cluster has no edge gateway.

Create Resource Exec Pty Session Ticket › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within the service to open a shell in.

The workload within the service to open a shell in.

id
​string · uuid · required · style: simple

Create Resource Exec Pty Session Ticket › query Parameters

container
​string | null · style: form

Which container of the pod the shell opens in. Omit it for the workload's own: the one its product configures, else its primary container. Must be a container the pod actually runs.

Which container of the pod the shell opens in. Omit it for the workload's own: the one its product configures, else its primary container. Must be a container the pod actually runs.

Default: null

Create Resource Exec Pty Session Ticket › Responses

A signed, single-use URL for opening a shell in one container

`POST /api/v2/service-instances/{id}/resources/{resource_id}/exec/session-ticket`.
container
​string · required

The container the shell will open in.

expires_at
​string · date-time · required

When the gateway stops accepting this ticket. A redemption deadline: the ticket is single use and the open session is bounded by the gateway's own idle and maximum-length timeouts, not by this.

shells
​string[] · required

The shells the gateway tries, in order, until one starts.

url
​string · required

The gateway URL to open a WebSocket against, carrying the signed ticket in its query string. Negotiate the zaroz-pty-v1 subprotocol and append columns and rows.


List Service Instance Files

GET
/api/v2/service-instances/{id}/resources/{resource_id}/files

Lists one directory on this workload's volume. path is absolute within the mount and is sent exactly as the customer typed it: kernel normalises it, and a client that collapsed .. itself would be papering over the layer that has to refuse it. The path in the response is the normalised one, so a breadcrumb reflects what was actually read rather than what was asked for, and a customer pasting an SFTP-shaped path gets back the mount-relative equivalent. Entries are unordered; sorting belongs to the panel. truncated is true when the directory holds more entries than one response carries, which is a flag rather than a cursor because the backend offers no stable ordering to page over. A path containing .., or naming one of the refused system prefixes, is a 400 rather than a 404: a traversal attempt and a missing file are different answers. 404 for a service whose product does not offer this capability, which is the same answer a service belonging to somebody else gives.

List Service Instance Files › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

List Service Instance Files › query Parameters

path
​string · required · style: form

Absolute within the mount, starting with /. Send it exactly as typed; normalising on the client would hide a traversal from the layer that has to refuse it.

Absolute within the mount, starting with /. Send it exactly as typed; normalising on the client would hide a traversal from the layer that has to refuse it.

List Service Instance Files › Responses

One directory's entries

One directory.
​FileEntryResponse[] · required

Unordered. Sorting is the panel's, per FilesTransport.

path
​string · required

The normalized path that was listed, not the one that was typed, so a breadcrumb reflects what kernel actually read. A customer pasting an SFTP-shaped path (/server/config) gets back the mount-relative one (/config).

truncated
​boolean · required

True when the directory holds more entries than one response carries. A flag rather than a cursor: there is no stable ordering to page over (the sidecar returns whatever read_dir yields), so a cursor would promise a consistency the backend cannot keep.


Delete Service Instance File

DELETE
/api/v2/service-instances/{id}/resources/{resource_id}/files

Removes one file or directory. Kernel reads the entry's kind itself and unlinks a file or removes a directory accordingly; the request never says which, because a client that claims "this is a file" is a client deciding what gets unlinked. recursive defaults to false and is required for a directory that is not empty, and kernel checks the directory itself rather than trusting the flag, so a client that forgets it deletes nothing rather than everything below the path. A delete naming the mount root is refused outright: emptying the volume is not a gesture a file browser should be able to reach, and a customer who genuinely wants it is asking to cancel the service.

Delete Service Instance File › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

Delete Service Instance File › query Parameters

path
​string · required · style: form
recursive
​boolean · style: form

Required for a directory that is not empty. Defaults to false, so a client that forgets it deletes nothing rather than everything.

Note what it does not do: it never chooses between unlinking a file and removing a tree. Kernel reads the entry's kind itself and dispatches on that, because a client that says "this is a file" is a client deciding what gets unlinked.

Required for a directory that is not empty. Defaults to false, so a client that forgets it deletes nothing rather than everything.

Note what it does not do: it never chooses between unlinking a file and removing a tree. Kernel reads the entry's kind itself and dispatches on that, because a client that says "this is a file" is a client deciding what gets unlinked.

Default: false

Delete Service Instance File › Responses

Removed

No data returned

Read Service Instance File

GET
/api/v2/service-instances/{id}/resources/{resource_id}/files/content

Reads one text file for the viewer. Capped at one mebibyte, and a larger file is refused with a message naming the cap rather than truncated: an editor that saved back a truncated read would destroy the tail of the customer's file. A file that is not valid UTF-8 is refused for the same reason, since the write route takes a string and a lossy read followed by a save would rewrite a binary as replacement characters. There is deliberately no route serving raw bytes or a signed download URL in this capability yet, so a client offers neither.

Read Service Instance File › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

Read Service Instance File › query Parameters

path
​string · required · style: form

Absolute within the mount, starting with /. Send it exactly as typed; normalising on the client would hide a traversal from the layer that has to refuse it.

Absolute within the mount, starting with /. Send it exactly as typed; normalising on the client would hide a traversal from the layer that has to refuse it.

Read Service Instance File › Responses

The file's text

One file's text.
content
​string · required

UTF-8 text. A file that is not valid UTF-8 is refused rather than lossily converted, because the transport's write takes a string and a lossy read followed by a save would rewrite the customer's binary as replacement characters.

path
​string · required
size_bytes
​integer · uint64 · min: 0 · required

Bytes of content, which is what was actually read rather than what the directory entry claimed a moment earlier.


Write Service Instance File

PUT
/api/v2/service-instances/{id}/resources/{resource_id}/files/content

Replaces one file's contents, creating it when it does not exist. Capped at one mebibyte, the same number the read is capped at, so a file the editor could open can always be saved back. Takes no operation lease: a file write is not a reconfiguration and does not re-render the workload, and holding the service's lease for the length of an editor save would refuse a restart for no reason. The audit entry names the path and the size and never the bytes.

Write Service Instance File › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

Write Service Instance File › query Parameters

path
​string · required · style: form

Absolute within the mount, starting with /. Send it exactly as typed; normalising on the client would hide a traversal from the layer that has to refuse it.

Absolute within the mount, starting with /. Send it exactly as typed; normalising on the client would hide a traversal from the layer that has to refuse it.

Write Service Instance File › Request Body

New contents for one file.
content
​string · required

Replaces the file's contents entirely. Creates it when it does not exist.

Write Service Instance File › Responses

The written file, as the backend now sees it

One entry in a listing.
kind
​FileKindResponse · enum · required

What an entry is. Two values, closed: a filesystem entry the browser can draw is a file or a directory, and the sidecar refuses to describe anything else (entry_for_path answers invalid_argument for a socket or a device).

Enum values:
file
directory
name
​string · required
path
​string · required

Absolute within the mount, always starting with /. This is the value to hand back to any other route on this capability: it is the sidecar's own answer about where the entry lives rather than a path the client rebuilt from name, so following it addresses the file kernel listed.

modified_at
​string | null · date-time

null when the backend reported none. Rendered, never parsed for meaning.

size_bytes
​integer | null · uint64 · min: 0

null for a directory. The sidecar reports zero for one, and a rendered zero reads as "this folder is empty", which is a claim kernel never made.


Create Service Instance Directory

POST
/api/v2/service-instances/{id}/resources/{resource_id}/files/directories

Creates one directory, and every missing parent along the way. Idempotent: creating a directory that already exists succeeds and returns it, which is what makes a retried request safe. The path travels in the body rather than the query string because this is the one route with no other reason to have one.

Create Service Instance Directory › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

Create Service Instance Directory › Request Body

Where to create a directory. The path travels in the body rather than the query string only because this is the one route with no other reason to have a body, and a `POST` whose entire input is a query parameter reads as a `PUT` that forgot its payload.
path
​string · required

Create Service Instance Directory › Responses

The directory, as the backend now sees it

One entry in a listing.
kind
​FileKindResponse · enum · required

What an entry is. Two values, closed: a filesystem entry the browser can draw is a file or a directory, and the sidecar refuses to describe anything else (entry_for_path answers invalid_argument for a socket or a device).

Enum values:
file
directory
name
​string · required
path
​string · required

Absolute within the mount, always starting with /. This is the value to hand back to any other route on this capability: it is the sidecar's own answer about where the entry lives rather than a path the client rebuilt from name, so following it addresses the file kernel listed.

modified_at
​string | null · date-time

null when the backend reported none. Rendered, never parsed for meaning.

size_bytes
​integer | null · uint64 · min: 0

null for a directory. The sidecar reports zero for one, and a rendered zero reads as "this folder is empty", which is a claim kernel never made.


Create Service Instance File Download URL

POST
/api/v2/service-instances/{id}/resources/{resource_id}/files/download-url

Mints a signed, short-lived hand-off to this service's own region for one file on this workload's volume (ZC-1225): a cluster edge gateway base URL plus a token, after running the identical confinement every interactive route on this capability runs. The signature names the path, not a connection: swapping path for another file's on an otherwise-valid ticket invalidates it, because the path is part of what was signed. The client downloads directly from the returned base_url using the returned token; kernel's own process never serves the bytes. This replaces a kernel-redeemed /api/v2/public URL this route used to return; the request and its authorization are unchanged.

Create Service Instance File Download URL › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

Create Service Instance File Download URL › Request Body

Which file to mint a signed download URL for. A body, not `?path=`, for the same reason `CreateDirectoryRequest` is: this `POST` has no other reason to carry one.
path
​string · required

Create Service Instance File Download URL › Responses

The signed hand-off, and when it expires

A signed hand-off to the region's own cluster edge gateway for the one file that was asked for (ZC-1225). This used to be `{ url, expires_at }`, a path on kernel's own `/api/v2/public` mount that kernel itself redeemed -- see `controllers/capabilities/files.rs`'s module header for why that hairpinned every download through kernel's own process regardless of which region the customer or the service were actually in. `base_url` is the cluster edge gateway's own address (e.g. `https://edge.mad.zaroz.cloud`) and `token` is the signed `edge_token::Resource::Sidecar` ticket, confined by its `root` to this exact file; the client opens the download directly against the gateway, and kernel's own process never touches the bytes. `expires_at` is the same instant the signature itself expires at, not a second, independently-computed deadline (`edge_token::sign_with_expiry` returns the one value used for both).
base_url
​string · required
expires_at
​string · date-time · required
token
​string · required

Create Service Instance Files Session Ticket

POST
/api/v2/service-instances/{id}/resources/{resource_id}/files/session-ticket

Mints a short-lived signed hand-off to this service's own region (ZC-1225): a cluster edge gateway base URL plus a token, confined to this workload's whole volume, for a client that will make many calls against cluster-agent's own /fs/* surface directly. Kernel's own process never touches the bytes of any operation opened this way. This is addressed by {service_instance_id, resource_id}, which is what lets a multi-workload instance name a second volume. Gated identically to download-url and for the same reason: a browse session is a wider grant than a single file, not a narrower one. 404 when the instance has no file provider or its cluster has no edge gateway configured.

Create Service Instance Files Session Ticket › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose volume is being browsed.

The workload within it whose volume is being browsed.

id
​string · uuid · required · style: simple

Create Service Instance Files Session Ticket › Responses

The signed hand-off, and when it expires

A signed hand-off to the region's own cluster edge gateway for a browse session across the whole volume (ZC-1225). The `/v2` re-keying of `/v1`'s `fs/edge-url` (`crates/http/workloads/src/controllers/fs.rs` on `dev`): `base_url` plus `token` is the identical two-field shape that route returned, so a client that already knows how to call cluster-agent's `/fs/*` surface with a `{base_url, token}` pair needs no new response parser. Unlike the download ticket above, this one's `token` is confined by `root` to the whole volume, not one file, because a browse session makes many `/fs/*` calls against the one ticket it was handed.
base_url
​string · required
expires_at
​string · date-time · required
token
​string · required

Create Resource Framebuffer Session Ticket

POST
/api/v2/service-instances/{id}/resources/{resource_id}/framebuffer/session-ticket

Mints a short-lived signed URL for one virtual machine's screen, through the cluster's edge gateway, and takes the exclusive hold that goes with it.

This is the machine's console, below its operating system. It sees the bootloader, it survives the guest's own firewall, and nothing inside the guest records what is done through it. Whoever can open it can do anything an operator sitting at the machine could.

Writes nothing durable, but it does take the hold. It is a POST because it produces a credential, because the audit entry is written before that credential is handed over, and because it acquires an exclusive session. Every call returns a different single-purpose URL.

The hold is exclusive; the socket is not, and the difference matters. Unlike createResourceCommandConsoleSessionTicket this route takes a hold, so a second caller gets a 409 naming the current holder and takes the screen only by asking for it with force. The hold lapses on its own if it is not refreshed through holdResourceFramebufferLock, so a browser that goes away does not keep a screen forever.

What the hold does not do is close a connection that is already open. The gateway checks the ticket once at the WebSocket upgrade and never consults the hold, so taking a screen with force stops the previous holder from refreshing and tells them they lost it, while their socket stays live and interactive until they disconnect. Treat the hold as the agreement between two well behaved clients that it is, not as an eviction. Closing the loser's socket is a change to the gateway and is not made here.

protocols names the WebSocket subprotocol the socket must request. It travels with the URL rather than being hardcoded by each client, because it is a property of the endpoint being minted; a socket that requests the wrong one completes the handshake with nothing to read.

expires_at is a redemption deadline, not a session deadline. The gateway checks the ticket once, at the WebSocket upgrade; the screen then stays connected until one side disconnects or the hold is taken. Redeem it immediately and do not re-mint to stay connected. hold_expires_at is the different, longer clock: refresh before it to keep the screen.

Note that a session opened through /v1's order-scoped vnc/edge-url and one opened here do not exclude each other. The two locks are keyed differently, because a service instance has no order to key on and may own more than one machine.

Gated on the permission to change the service, not the permission to see it. 404 when the instance has no framebuffer, when the named resource is not one of its virtual machines, or when its cluster has no edge gateway configured.

Create Resource Framebuffer Session Ticket › path Parameters

resource_id
​string · uuid · required · style: simple

The virtual machine within it whose screen is being opened.

The virtual machine within it whose screen is being opened.

id
​string · uuid · required · style: simple

Create Resource Framebuffer Session Ticket › query Parameters

force
​boolean · style: form

Take the screen from whoever currently holds it.

A deliberate act, not a retry: a client sends it only after a 409 and only because somebody chose to take over. The previous holder is not notified by kernel; their next hold refresh returns held: false and names the new holder.

Take the screen from whoever currently holds it.

A deliberate act, not a retry: a client sends it only after a 409 and only because somebody chose to take over. The previous holder is not notified by kernel; their next hold refresh returns held: false and names the new holder.

Default: false

Create Resource Framebuffer Session Ticket › Responses

A signed, short-lived URL for one machine's screen, and the hold

`POST /api/v2/console/service-instances/{id}/resources/{resource_id}/framebuffer/session-ticket`.
expires_at
​string · date-time · required

When the gateway stops accepting this ticket.

A redemption deadline and not a session deadline: cluster-agent verifies exp once at upgrade (gateway/vnc.rs:12) and never again, so an attached screen outlives its ticket.

hold_expires_at
​string · date-time · required

When the exclusive hold lapses unless refreshed.

protocols
​string[] · required

Subprotocols the socket must request. See [FRAMEBUFFER_SUBPROTOCOL].

session_id
​string · required

The handle for this exclusive session.

Minted here rather than supplied by the client, unlike /v1's sessionId query parameter. The client cannot then name somebody else's session, and taking a screen over is spelled force rather than spelled "guess the holder's identifier and refresh it".

Pass it to the hold and release routes. It is not a credential: holding this screen still requires passing the same authorization the mint did.

url
​string · required

The gateway URL to open a WebSocket against, carrying the signed ticket in its query string.


Hold Resource Framebuffer Lock

POST
/api/v2/service-instances/{id}/resources/{resource_id}/framebuffer/lock

Refreshes the exclusive hold on one virtual machine's screen. A client calls this on a timer well inside the hold's lifetime while it is connected.

Losing the screen is a 200 carrying held: false, not an error. By the time a hold is lost the caller is no longer the one using the screen, and putting a failure in front of them would report a problem to the wrong person. The response names the new holder so a client can say who took it.

A hold that has already lapsed is simply re-taken, provided nothing else has claimed the screen in between: a keep-alive arriving one request late should not strand a client that still has the session open.

The hold exists because two pointers on one screen fight over one cursor. createResourceCommandConsoleSessionTicket deliberately has no equivalent, because several people watching one game server's console is normal and correct.

Hold Resource Framebuffer Lock › path Parameters

resource_id
​string · uuid · required · style: simple

The virtual machine within it whose screen is being opened.

The virtual machine within it whose screen is being opened.

id
​string · uuid · required · style: simple

Hold Resource Framebuffer Lock › Request Body

Body of `POST /api/v2/console/service-instances/{id}/resources/{resource_id}/framebuffer/lock`.
session_id
​string · required

The session_id the ticket response minted. A session that no longer holds the screen gets held: false rather than an error.

Hold Resource Framebuffer Lock › Responses

Whether the screen is still held, and by whom if not

`POST /api/v2/console/service-instances/{id}/resources/{resource_id}/framebuffer/lock`. A keep-alive, so losing the screen is a normal 200 carrying `held: false` rather than an error. `zaroz-ui`'s `FramebufferHold` is `{ held: true } | { held: false; holder?: string }` for the same reason: a panel that has been taken over surrenders the screen, it does not report a failure to the customer who is no longer using it.
held
​boolean · required
expires_at
​string | null · date-time

When this hold lapses unless refreshed again. Absent when the hold was lost, because there is nothing left to refresh.

holder_name
​string | null

Who holds it instead, when the hold was lost. Absent when it was kept, and absent when nothing holds it at all.


Release Resource Framebuffer Lock

DELETE
/api/v2/service-instances/{id}/resources/{resource_id}/framebuffer/lock

Gives one virtual machine's screen back, so the next person does not wait out the hold's expiry.

/v1 has no equivalent and a closing tab there leaves the screen held for the rest of the lifetime, which is the gap this closes. It is best effort by design: a session that no longer holds the screen releases nothing and gets released: false rather than an error, because the ordinary caller is a page being torn down and that is not a place to report a problem.

Releasing a hold does not close an already-connected socket. The gateway checks the ticket at upgrade and never consults the hold, so a client that releases must also disconnect.

Release Resource Framebuffer Lock › path Parameters

resource_id
​string · uuid · required · style: simple

The virtual machine within it whose screen is being opened.

The virtual machine within it whose screen is being opened.

id
​string · uuid · required · style: simple

Release Resource Framebuffer Lock › query Parameters

session_id
​string · required · style: form

The session giving the screen back. A session that no longer holds it releases nothing, which is the ordinary outcome after being taken over.

The session giving the screen back. A session that no longer holds it releases nothing, which is the ordinary outcome after being taken over.

Release Resource Framebuffer Lock › Responses

Whether this session was the one holding the screen

`DELETE /api/v2/console/service-instances/{id}/resources/{resource_id}/framebuffer/lock`.
released
​boolean · required

False when the session named no longer held the screen, which is the ordinary outcome of unmounting after being taken over. Not an error: a page being torn down is not a place to report one.


Get Resource Logs

GET
/api/v2/service-instances/{id}/resources/{resource_id}/logs

Reads one container's retained output, oldest first. This is the backlog half of LogStream; createResourceLogStreamTicket is the live half.

It reads the retained window, not history. There is no log store on this platform. The Kubernetes log API serves only what the node's log rotation still holds, so an empty result means "not in the retained window" and never "never happened". The coverage field is kernel's own sentence naming what was actually read, and a consumer should show it beside the results rather than paraphrasing it.

search is a case-insensitive substring, not a regular expression, and it runs here rather than in the browser: filtering client-side only ever filters the window the browser happens to be holding, and the window read here is far larger than that and is discarded server-side before any non-matching line is sent.

cursor is opaque and resumes exactly. It carries the instant a previous response stopped at together with how many lines bearing that same instant were already returned, because Kubernetes timestamps are not unique within a nanosecond and resuming on an instant alone either repeats or drops the lines sharing it.

There is deliberately no until parameter. The Kubernetes log API has no such bound, and implementing one by trimming a tail-anchored read would return an empty page for any range that ends before the newest output, which reads as "nothing happened then". A real time range needs a log store, which is its own programme.

A line carries no stream and no level. The log API merges stdout and stderr with no marker, and nothing on this platform parses a severity; both are optional in the client contract precisely so neither has to be invented here.

Get Resource Logs › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose output is being read.

The workload within it whose output is being read.

id
​string · uuid · required · style: simple

Get Resource Logs › query Parameters

container
​string | null · style: form

Which container on the workload's pod. May be omitted when the pod runs exactly one, which is the common case; a multi-container pod requires it and the refusal names the containers to choose from.

Which container on the workload's pod. May be omitted when the pod runs exactly one, which is the common case; a multi-container pod requires it and the refusal names the containers to choose from.

Default: null
cursor
​string | null · style: form

A next_cursor from an earlier response. Opaque; hand back exactly what was given.

A next_cursor from an earlier response. Opaque; hand back exactly what was given.

Default: null
limit
​integer | null · uint32 · min: 0 · style: form

Most lines to return. Clamped rather than rejected: a caller asking for more than the ceiling wants as much as possible.

Most lines to return. Clamped rather than rejected: a caller asking for more than the ceiling wants as much as possible.

Default: null
previous
​boolean | null · style: form

Read the previous, terminated instance of the container instead of the running one. The only way to see why a crash-looping container died.

Read the previous, terminated instance of the container instead of the running one. The only way to see why a crash-looping container died.

Default: null
search
​string | null · style: form

Case-insensitive substring, applied on the server before the lines reach the browser. Not a regular expression.

Case-insensitive substring, applied on the server before the lines reach the browser. Not a regular expression.

Default: null

Get Resource Logs › Responses

The retained window, oldest first, with a cursor to continue from

`GET /api/v2/console/service-instances/{id}/resources/{resource_id}/logs`.
container
​string · required

The container these lines came from. Always populated, including when the request named none and the workload runs exactly one.

containers
​string[] · required

Every container on this workload's current pod, so a panel can offer a container picker without a second call. A workload with one container yields one entry, and a panel should render no picker for it rather than a select with a single option.

coverage
​string · required

Kernel's own sentence about what was actually read, to be shown beside the results rather than paraphrased or composed in the browser (R2).

It exists because of one specific way this endpoint can mislead: there is no log store on this platform, so a search covers only the window node log rotation still holds. A customer searching for a line that scrolled out of that window must be told what was searched, not shown an empty result that reads as "it never happened".

​LogLineResponse[] · required

Oldest first, which is reading order for a log.

truncated
​boolean · required

true when the read hit its own bounds, so more output exists on either side of what was returned.

next_cursor
​string | null

Hand this back as cursor to continue forwards from where these lines stopped. Opaque: its spelling may change.

search
​string | null

Echoed back so a client can tell a response to its current filter from a late response to the previous one.


Create Resource Log Stream Ticket

POST
/api/v2/service-instances/{id}/resources/{resource_id}/logs/stream-ticket

Mints a short-lived signed URL for following one container's output live, through the cluster's own edge gateway. This is the live half of LogStream; getResourceLogs is the backlog half.

Writes nothing the caller can read back through this API, and one thing they can read elsewhere: the grant is recorded in the owning organization's audit feed as service_instance.log_stream_attached, written before the credential is handed over, the same ordering the command-console and framebuffer mints use. The entry names the container, which neither of those can, and never the token.

It is a POST because it produces a credential: every call returns a different single-purpose URL, and a GET that does that is one a browser, a proxy or a history entry will cache and replay.

The transport is a WebSocket, and that was a decision rather than an assumption. SSE was the alternative and was rejected on four grounds. A PTY needs keystrokes and resize messages travelling the other way, so choosing SSE here would guarantee the platform runs two transports rather than one. Five of the six endpoints on this gateway's router are already WebSocket upgrades and exactly one is SSE, so SSE would be a second convention rather than a replacement. The signed ticket is shared machinery across four resource kinds and would have to be reimplemented over an EventSource, which cannot send an Authorization header and would push the token into a query string on a long-lived connection. And SSE's one real advantage, Last-Event-ID, is the wrong granularity: the cursor this design needs is a property of the upstream read, not of the frame numbering, and has to be re-supplied on a fresh ticket regardless. The consequence accepted with it is that a WebSocket gives no automatic reconnect, so the reconnect ladder is a shared client concern.

There is no search here, and there cannot be one while kernel stays off the data path: the live bytes go from the cluster to the browser without passing through this process. Filtering the tail is a client concern; getResourceLogs is where a search runs on the server.

The ticket names exactly one container, and the gateway refuses any other, so a client switching containers mints a new one. It is valid for a minute; a client that wants to keep reading re-mints, which is what keeps a leaked URL from being a durable credential.

since is the resume cursor for the live half: pass the at of the last line already on screen and it is signed into the returned URL as since_time. The gateway reads it, clamps it to its own lookback bound, and uses it INSTEAD of the tail replay, so a reconnect resumes where the client stopped rather than repeating what it already holds. A malformed value degrades to the tail replay rather than failing the connection, so a client that sends a bad cursor still gets output. Omit it on a first connection, when there is nothing to resume from and the tail is what you want.

previous=true follows the container's previous, terminated instance instead of the running one, which is the only way to see why a crash-looping container died. It is signed into the ticket, so a ticket minted without it cannot be edited into one that reads the crashed instance. A terminated instance writes nothing further, so the stream closes once its retained output has been sent. It combines with since: the resume point applies to the previous instance's output.

Create Resource Log Stream Ticket › path Parameters

resource_id
​string · uuid · required · style: simple

The workload within it whose output is being read.

The workload within it whose output is being read.

id
​string · uuid · required · style: simple

Create Resource Log Stream Ticket › query Parameters

container
​string | null · style: form

Which container the ticket is minted for. May be omitted when the pod runs exactly one.

Which container the ticket is minted for. May be omitted when the pod runs exactly one.

Default: null
previous
​boolean | null · style: form

Follow the previous, terminated instance of the container instead of the running one. The only way to see why a crash-looping container died.

Follow the previous, terminated instance of the container instead of the running one. The only way to see why a crash-looping container died.

Default: null
since
​string | null · style: form

RFC3339 instant to resume the stream from, normally the at of the last line already on screen.

RFC3339 instant to resume the stream from, normally the at of the last line already on screen.

Default: null

Create Resource Log Stream Ticket › Responses

A signed, short-lived URL for one container's live output

`POST /api/v2/console/service-instances/{id}/resources/{resource_id}/logs/stream-ticket`.
container
​string · required

The container the ticket is minted for. The gateway refuses any other, so a client switching containers mints a new ticket.

expires_at
​string · date-time · required

When the ticket stops being accepted. A client re-mints on expiry; the short life is what makes a leaked URL harmless.

url
​string · required

The gateway URL to open a WebSocket against. Carries the signed ticket in its query string and is single-purpose: it grants a read of exactly one container's output and nothing else.


Get Resource Metrics

GET
/api/v2/service-instances/{id}/resources/{resource_id}/metrics

Reads one resource's CPU, memory and network over a chosen window, as points already bucketed by the backend. window_minutes is 5, 15 or 30 and defaults to 30; anything else is refused, because metric retention is thirty minutes and a longer window has no samples to draw. Every window returns 60 buckets, so the bucket width is 5, 15 or 30 seconds respectively. A bucket holding no samples has a null value so a chart can break the line, which a stopped workload and an idle one need to look different. Each series carries a summary -- latest, mean and max over the whole window, computed from the raw samples rather than from the buckets, so a one-sample spike is still reported as the max -- and the ceiling it is measured against, or null where the series is unmetered. The summary is absent when the window holds no samples at all.

Get Resource Metrics › path Parameters

id
​string · uuid · required · style: simple
resource_id
​string · uuid · required · style: simple

The resource within it whose measurements are wanted. Scoped per resource rather than per instance because a Supabase-shaped instance owns six workloads, and "CPU" is not one number across them.

The resource within it whose measurements are wanted. Scoped per resource rather than per instance because a Supabase-shaped instance owns six workloads, and "CPU" is not one number across them.

Get Resource Metrics › query Parameters

window_minutes
​integer · uint32 · min: 0 · style: form

Window in minutes, ending now. One of 5, 15 or 30; anything else is refused rather than clamped, because silently widening a window makes two screens disagree about what "the last five minutes" showed.

Window in minutes, ending now. One of 5, 15 or 30; anything else is refused rather than clamped, because silently widening a window makes two screens disagree about what "the last five minutes" showed.

Default: 30

Get Resource Metrics › Responses

Every series for this resource over the requested window

Every series for one resource over one window.
coverage
​string · required

Kernel's own sentence about what was actually read, to be shown beside the charts rather than paraphrased or composed in the browser (R2). The same field, for the same reason, as [ResourceLogsResponse::coverage] -- named precisely because 00-program.md 15.3.1 calls it LogSearchResponse, which does not exist, and a citation drift is how the next reader loses ten minutes.

It exists because of one specific way this endpoint misleads. Every window returns [METRIC_BUCKETS] buckets whether or not anything was sampled, so a resource with no samples at all comes back as four series of sixty nulls -- four empty axes, no summary, and nothing said. A consumer cannot tell that apart from a workload that was genuinely stopped for the whole window, and it must not try: deciding which from the points is exactly the reduction R2 forbids.

So kernel says which it is. The distinction the sentence carries is "no sample was stored" versus "usage was zero", and only the server knows it.

from
​string · date-time · required

Start of the first bucket.

resolution_seconds
​integer · uint32 · min: 0 · required

Bucket width, in seconds. (to - from) / resolution_seconds is the length of every points array in series.

​MetricSeriesResponse[] · required
to
​string · date-time · required

End of the window. Exclusive: no bucket contains it.

window_minutes
​integer · uint32 · min: 0 · required

The window actually served, echoed so a client can tell what it got without re-deriving it from its own request.


Get Resource SSH Connection Details

GET
/api/v2/service-instances/{id}/resources/{resource_id}/ssh

How to reach one Linux virtual machine over SSH, and whether its browser terminal is ready.

host, port, username and command are for the customer's own SSH client; host is empty while the machine has no public address of its own. authorized_key_fingerprints are the keys the machine was built trusting, and host_key_fingerprints the ones it enrolled for itself on first boot, which a client should see on its first connection.

browser_ssh_status is ready only when the machine is running, its host key is enrolled and its cluster's SSH broker is healthy; enrolling_host_key while the guest has not reported its key yet; otherwise unavailable. public_route_status is ready once the machine's public address routes to it.

Gated on the permission to change the service, like the session route beside it: nothing here is useful except to someone about to open a shell. 404 when the instance has no SSH capability or the resource is not one of its virtual machines; 503 when the machine cannot take an SSH session.

Get Resource SSH Connection Details › path Parameters

resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

Get Resource SSH Connection Details › Responses

How to reach the machine, and whether the browser terminal is ready

`GET /api/v2/service-instances/{id}/resources/{resource_id}/ssh`.
authorized_key_fingerprints
​string[] · required

SHA-256 fingerprints of the public keys the machine was built trusting.

browser_ssh_status
​string · required

ready, enrolling_host_key or unavailable.

command
​string · required

A ready-to-paste ssh user@host, or empty while there is no host.

host
​string · required

The machine's own public address, or empty while it has none.

host_key_fingerprints
​string[] · required

SHA-256 fingerprints of the host keys the machine enrolled on first boot: what a client should see on its first connection.

operating_system
​string · required

Always linux: the capability is only derived for a Linux guest.

password_auth_enabled
​boolean · required
port
​integer · uint16 · min: 0 · max: 65535 · required
public_route_status
​string · required

ready once the public address routes to the machine, else pending.

username
​string · required

The guest account the machine was built with.


Get Resource VPS Details

GET
/api/v2/service-instances/{id}/resources/{resource_id}/vps-details

The details panel's read for one virtual machine, Linux or Windows: the operating system, the guest account, the public IPv4 and IPv6 addresses, the internal addresses the guest reports, and where to connect (SSH on 22 for Linux, RDP on 3389 for Windows). The password is never included. Internal addresses come from the running guest and are null while it is stopped or its cluster cannot answer.

Gated like the SSH details read beside it. 404 when the instance has no SSH capability or the resource is not one of its virtual machines.

Get Resource VPS Details › path Parameters

resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

Get Resource VPS Details › Responses

The machine's addresses and where to connect

What the VPS details panel shows for a machine of either OS (V-0712): v1's `VpsDetailsView` (OS, account, public IPv6, internal addresses) plus where to connect, which for a Windows guest is RDP.
connect_port
​integer · uint16 · min: 0 · max: 65535 · required

22 for Linux (SSH), 3389 for Windows (RDP).

connect_protocol
​string · required

ssh or rdp.

operating_system
​string · required

linux or windows.

public_ipv4
​string · required

The machine's public IPv4 address; empty while it has none.

username
​string · required
internal_ipv4
​string | null
internal_ipv6
​string | null
public_ipv6
​string | null

Create Resource SSH Session

POST
/api/v2/service-instances/{id}/resources/{resource_id}/ssh/sessions

Issues a browser SSH session on one Linux virtual machine and returns the one-time URL its terminal connects to.

This is a shell on the customer's machine, as the guest account it was built with. The URL is redeemable once, within expires_in seconds, by the cluster's SSH broker, and only from the dashboard origin in the X-Zaroz-Dashboard-Origin header the request carried; a request without that header is refused. The broker then connects with a certificate valid for one minute, and the session is re-authorized on every heartbeat, so it ends within one heartbeat of the caller losing access to the service.

Browser sessions only: a restricted API token is refused with 403, because its narrower scope could not be re-applied on those heartbeats.

Unlike the framebuffer there is no exclusive hold; several terminals on one machine are normal. The limit is three live sessions per person per machine, and a fourth is refused with 429.

Gated on the permission to change the service. 404 when the instance has no SSH capability or the resource is not one of its virtual machines; 503 when the machine is not running, its host key is not enrolled yet, or its cluster's SSH broker is not healthy.

Create Resource SSH Session › path Parameters

resource_id
​string · uuid · required · style: simple
id
​string · uuid · required · style: simple

Create Resource SSH Session › Request Body

`POST /api/v2/service-instances/{id}/resources/{resource_id}/ssh/sessions`. Every field is optional and none changes what is issued: the terminal size and correlation id are accepted so the dashboard's existing client can send what it already sends, and are bounded so they cannot be used to push arbitrary data through.
columns
​integer | null · uint32 · min: 0
Default: null
correlation_id
​string | null
Default: null
rows
​integer | null · uint32 · min: 0
Default: null

Create Resource SSH Session › Responses

A one-time URL for the browser terminal

The one-time URL a browser terminal connects to.
expires_in
​integer · uint64 · min: 0 · required
session_id
​string · uuid · required
url
​string · required

wss://<edge>/ssh?ticket=.... Redeemable once, within expires_in seconds, and only from the dashboard origin it was issued for.


Get Service Instance Volume

GET
/api/v2/service-instances/{id}/resources/{resource_id}/volume

Kernel's own summary of one volume, so a client never sums file sizes or divides two byte counts to draw a meter. capacity_bytes is the claim's configured size, which is a quota rather than a measurement and is therefore always present. used_bytes is a recursive walk performed inside the cluster and is null whenever kernel cannot measure exactly this volume: the service has no file sidecar, the sidecar's walk covers more than this claim, or the walk did not finish in time. used_label and used_fraction are kernel's rendering of the same measurement and are null exactly when it is; render the label as written and treat the fraction as already clamped to [0, 1]. last_backup_at is the customer's most recent completed on-demand backup of this volume and never the platform's own disaster-recovery backups. There is no measurement timestamp, because the backend caches its walk and reports neither its age nor its duration, so any timestamp here would be the time kernel asked rather than the time anything was measured. 404 for a resource that is not a volume, for a volume belonging to somebody else, and for a service whose product has no storage, which are deliberately the same answer.

Get Service Instance Volume › path Parameters

resource_id
​string · uuid · required · style: simple

The volume within it being described.

The volume within it being described.

id
​string · uuid · required · style: simple

Get Service Instance Volume › Responses

Everything kernel knows about this volume

Kernel's own summary of the storage behind one service.
capacity_bytes
​integer · uint64 · min: 0 · required

The claim's configured size. A quota rather than a measurement, so it is exactly what the customer bought and it never disagrees with the invoice.

mount_path
​string · required

Where the volume is bound inside the workload, for example /data. A cross reference rather than a property of the claim: the mount lives on the workload that mounts it, and this is the path the file browser opens at for the same volume.

last_backup_at
​string | null · date-time

When the customer's most recent on-demand backup of this volume finished, or null when they have never taken one that completed.

The customer's own snapshots only. The platform's disaster-recovery backups run on a different mechanism and are not counted here, because presenting one as the other would tell a customer their data is protected by something they never invoked.

used_bytes
​integer | null · uint64 · min: 0

What the volume holds, or null when kernel cannot measure exactly this claim: the service has no file sidecar, the sidecar's walk covers more than this volume, or it did not answer in time. Absent rather than approximated.

used_fraction
​number | null · double

A number in [0, 1], already clamped. Multiplying it by 100 for a percentage width is a unit conversion for the widget rather than a computation; deriving it from the two byte counts instead is not. null exactly when used_bytes is.

used_label
​string | null

Kernel's sentence about the meter, for example "3.0 GiB of 25 GiB". Render it as written. null exactly when used_bytes is.