AdminService
AdminService manages installation-wide settings, user management, and resource presets. Only accessible to instance administrators.
AddAllowedEmail
Section titled “AddAllowedEmail”POST /spin.v1.AdminService/AddAllowedEmail
Add allowed email/domain
Request
| Field | Type | What it is |
|---|---|---|
pattern | string | Email address (user@example.com) or domain (example.com) |
type | AllowedEmailType | |
description | string | Optional description |
Response
| Field | Type | What it is |
|---|---|---|
entry | AllowedEmail |
CreateNetworkPolicy
Section titled “CreateNetworkPolicy”POST /spin.v1.AdminService/CreateNetworkPolicy
Request
| Field | Type | What it is |
|---|---|---|
policy | NetworkPolicyRule |
Response
No fields: {}.
CreateResourcePreset
Section titled “CreateResourcePreset”POST /spin.v1.AdminService/CreateResourcePreset
Create a resource preset
Request
| Field | Type | What it is |
|---|---|---|
name | string | Required: display name |
description | string | Optional: description |
cpuCores | integer (int32) | Required: CPU cores |
memoryMb | integer (int32) | Required: memory in MB |
diskGb | integer (int32) | Required: disk in GB |
burst | BurstMode | Required |
isDefault | boolean | Optional: make this the default |
enabled | boolean | Optional: enable the preset (default true) |
sortOrder | integer (int32) | Optional: display order |
burstFloorCpuCores | integer (int32) | Required for a burst mode: what its workspaces start with, at most the preset’s size. |
burstFloorMemoryMb | integer (int32) | |
bandwidthMbps | integer (int32) | What a workspace of it may carry each way, in megabits a second; 0 is unshaped. |
rpoSeconds | integer (int32) | How far behind the object store a workspace of it may fall, in seconds; 0 is the installation’s. |
Response
| Field | Type | What it is |
|---|---|---|
preset | ResourcePreset |
DecideConfigChange
Section titled “DecideConfigChange”POST /spin.v1.AdminService/DecideConfigChange
Apply a change the file proposes, or dismiss it. Either is remembered until the file says something else again. Audited with the admin who decided.
Request
| Field | Type | What it is |
|---|---|---|
kind | ConfigItemKind | |
name | string | |
says | string | ConfigChange.says, as listed. |
apply | boolean | True writes what the file says; false keeps what the installation has. |
Response
No fields: {}.
DeleteNetworkPolicy
Section titled “DeleteNetworkPolicy”POST /spin.v1.AdminService/DeleteNetworkPolicy
Refused while a workspace runs under the policy or it is the installation’s default.
Request
| Field | Type | What it is |
|---|---|---|
name | string |
Response
No fields: {}.
DeleteResourcePreset
Section titled “DeleteResourcePreset”POST /spin.v1.AdminService/DeleteResourcePreset
Delete a resource preset
Request
| Field | Type | What it is |
|---|---|---|
id | string | Required: preset ID to delete |
Response
No fields: {}.
ExplainStorageKey
Section titled “ExplainStorageKey”POST /spin.v1.AdminService/ExplainStorageKey
What one key in the store is, and whose: a key read off the bucket’s console says nothing a person can act on.
Request
| Field | Type | What it is |
|---|---|---|
key | string |
Response
| Field | Type | What it is |
|---|---|---|
what | string | What the object is, in words. |
volume | StoredVolume | Whose it is, when it is a volume’s. |
GetBill
Section titled “GetBill”POST /spin.v1.AdminService/GetBill
What the installation cost in a month, as its cloud’s bill says: by day and service, what the month is forecast to end at, and its budget. As the control plane last read the bill - a few times a day (internal/controlplane/domain/bill) - never the cloud itself, where every question to its billing is billed.
Request
| Field | Type | What it is |
|---|---|---|
month | Timestamp | The month, as any instant in it (UTC’s); unset is the month in progress. |
Response
| Field | Type | What it is |
|---|---|---|
month | Timestamp | The month’s first instant, UTC. |
readAt | Timestamp | When the bill was last read; unset where it never was - no scope (bill_scope), or a cloud that sends none - and then nothing below is known. |
currency | string | ISO 4217; every amount here is in millionths of it. |
totalMicros | string (int64) | The month so far, every day and service. |
forecastMicros | string or null (int64) | What the month is forecast to end at; unset where the cloud has no forecast yet. |
budgetLimitMicros | string or null (int64) | The installation’s budget and what the cloud counts against it; unset where it has none. |
budgetActualMicros | string or null (int64) | |
budgetForecastMicros | string or null (int64) | |
days | list of BillDay | Oldest first. |
GetCosts
Section titled “GetCosts”POST /spin.v1.AdminService/GetCosts
A month of the bill shared out to the workspaces that caused it: the runners’ by what each workspace held of them, the volumes’ bucket by what its volumes kept. What nobody caused is said apart and never spread: the runners’ capacity nobody held, the bucket’s bytes no workspace keeps, and the platform’s own cost by service (internal/controlplane/domain/finops).
Request
| Field | Type | What it is |
|---|---|---|
month | Timestamp | The month, as any instant in it (UTC’s); unset is the month in progress. |
Response
| Field | Type | What it is |
|---|---|---|
month | Timestamp | The month’s first instant, UTC. |
currency | string | ISO 4217; every amount here is in millionths of it. |
workspaces | list of WorkspaceCost | Costliest first. |
idleMicros | string (int64) | What the runners cost that no workspace held. |
unstoredMicros | string (int64) | What the volumes’ bucket cost for bytes no workspace keeps: the images, what nothing references any more. |
platform | list of ServiceCost | Every other cost - the control plane, the proxy, keys, logs - by service, costliest first. |
GetFleetVersions
Section titled “GetFleetVersions”POST /spin.v1.AdminService/GetFleetVersions
What is running where: this control plane, each host’s runner and machine, and the extension releases workspaces are on. An installation is updated in halves, and this is the one page that says which halves it is in.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
controlPlaneVersion | string | |
machineVersion | string | The spin-machine release this control plane pins, which a host should be running. |
hosts | list of FleetHostVersion | |
extensions | list of ExtensionVersion |
GetInstallationSettings
Section titled “GetInstallationSettings”POST /spin.v1.AdminService/GetInstallationSettings
Get installation settings
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
settings | InstallationSettings |
GetMonitoring
Section titled “GetMonitoring”POST /spin.v1.AdminService/GetMonitoring
The Grafana the control plane serves over the installation’s metrics, and the release’s dashboards in it.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
grafana | Grafana | Unset where the control plane serves none: the installation keeps no metrics, or this machine has no Grafana. |
GetPlatformImages
Section titled “GetPlatformImages”POST /spin.v1.AdminService/GetPlatformImages
Whether the base image and the supervisor this control plane’s image carries are published.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
images | list of PlatformImage | Empty until the object store is configured: there is nowhere to publish to. |
baseImages | list of BaseImage | Every base image published, one per machine release, newest first. |
supervisorReleases | list of ExtensionRelease | Every release of the supervisor, newest first. |
agentReleases | list of ExtensionRelease | Every release of the agent CLIs (Claude Code and Codex, one extension), newest first. |
GetRegistrationMode
Section titled “GetRegistrationMode”POST /spin.v1.AdminService/GetRegistrationMode
Get registration mode (open, whitelist, closed)
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
mode | RegistrationMode |
GetSecuritySettings
Section titled “GetSecuritySettings”POST /spin.v1.AdminService/GetSecuritySettings
Get security settings
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
settings | SecuritySettings |
GetStorageSettings
Section titled “GetStorageSettings”POST /spin.v1.AdminService/GetStorageSettings
Where the installation’s object store is. The secret is never read back.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
settings | StorageSettings | |
volumesExist | boolean | Whether volumes exist, whose history is in this store: it can then be changed, but not for another bucket or directory. |
GetStorageUsage
Section titled “GetStorageUsage”POST /spin.v1.AdminService/GetStorageUsage
What the store holds, by what each object is for: every volume’s objects and the layers its commits name, with the workspace, image or extension release it is. As the storage-gc job last read it - daily, or when an admin runs it - never the bucket itself.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
volumes | list of StoredVolume | Heaviest first. |
unreferencedLayers | StorageTally | Layers no commit in the store names: the storage GC’s to collect. |
other | StorageTally | Everything outside volumes/ and layers/: the control plane’s election records. |
measuredAt | Timestamp |
GetTelemetryStatus
Section titled “GetTelemetryStatus”POST /spin.v1.AdminService/GetTelemetryStatus
What the collector has sent and failed to send over its last minute, as the watch on its machine read it from the collector itself.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
reportedAt | Timestamp | Unset: the watch has not reported since this control plane started - no collector, or not yet. |
windowSeconds | integer (int32) | How long the counts below are over. |
spans | TelemetryFlow | Into the installation’s store, after the traces policy chose which to keep. |
samples | TelemetryFlow | Into the installation’s store of metrics. |
GetVSCodeServers
Section titled “GetVSCodeServers”POST /spin.v1.AdminService/GetVSCodeServers
The VS Code servers workspaces are given (the vscode-server extension): each release, and the publish this control plane ran since it started, if it ran one.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
releases | list of ExtensionRelease | Newest first. |
publish | VSCodeServerPublish | |
unavailable | string | Why this control plane cannot publish - no object store, or a build with no machine tools to make the image with - and empty when it can. |
ListAllowedEmails
Section titled “ListAllowedEmails”POST /spin.v1.AdminService/ListAllowedEmails
List allowed emails/domains
Request
| Field | Type | What it is |
|---|---|---|
page | PageRequest |
Response
| Field | Type | What it is |
|---|---|---|
entries | list of AllowedEmail | |
page | PageResponse |
ListAuditLog
Section titled “ListAuditLog”POST /spin.v1.AdminService/ListAuditLog
Read the audit log, newest first. There is no RPC that writes one: an entry is written by the operation it records, so a log an API could add to would be one an API could forge.
Request
| Field | Type | What it is |
|---|---|---|
page | PageRequest | |
actorId | string | Each filter is optional and they are combined with AND; an empty request is the whole log, newest first. |
action | string | |
resourceType | string | |
since | Timestamp | since bounds the listing at the older end; an audit log is read forward from an incident, and the whole of one is not what a page wants. |
Response
| Field | Type | What it is |
|---|---|---|
entries | list of AuditEntry | |
page | PageResponse | |
actions | list of string | actions and resource_types are every value this installation can record, so a reader building a filter does not have to know them. They come from the code rather than from a DISTINCT over the log: the log is the one table that only grows, and a vocabulary that is empty until something happens is a filter that is empty when it matters. |
resourceTypes | list of string | |
totalCapped | boolean | total_capped says page.total_count is where counting stopped, not the count: the log is counted up to a bound, since counting all of it is reading all of it on every page. |
ListConfigChanges
Section titled “ListConfigChanges”POST /spin.v1.AdminService/ListConfigChanges
What the config file says now and the installation does not, for an administrator to decide: the file seeds an installation once, and after that its changes are proposals.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
changes | list of ConfigChange |
ListJobRuns
Section titled “ListJobRuns”POST /spin.v1.AdminService/ListJobRuns
One job’s runs, newest first.
Request
| Field | Type | What it is |
|---|---|---|
job | string | |
limit | integer (int32) | At most this many, newest first; zero is the default of 50. |
Response
| Field | Type | What it is |
|---|---|---|
runs | list of JobRun |
ListJobs
Section titled “ListJobs”POST /spin.v1.AdminService/ListJobs
The control plane’s periodic work - backups, cleanups, the object store’s garbage collection - with how often each runs and how its last run went.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
jobs | list of Job |
ListRekeys
Section titled “ListRekeys”POST /spin.v1.AdminService/ListRekeys
The disks being re-keyed, and the ones a revoked host’s keys marked for it.
Request
No fields: {}.
Response
| Field | Type | What it is |
|---|---|---|
rekeys | list of VolumeRekey |
ListResourcePresets
Section titled “ListResourcePresets”POST /spin.v1.AdminService/ListResourcePresets
List resource presets
Request
| Field | Type | What it is |
|---|---|---|
includeDisabled | boolean | Include disabled presets (admin only) |
page | PageRequest |
Response
| Field | Type | What it is |
|---|---|---|
presets | list of ResourcePreset | |
page | PageResponse |
ListUserAPIKeys
Section titled “ListUserAPIKeys”POST /spin.v1.AdminService/ListUserAPIKeys
List another user’s API keys. The secret is never stored, so this is what an admin can know about a key: what it is called, when it was made, when it was last used.
Request
| Field | Type | What it is |
|---|---|---|
userId | string | |
page | PageRequest |
Response
| Field | Type | What it is |
|---|---|---|
apiKeys | list of APIKey | |
page | PageResponse |
ListUsers
Section titled “ListUsers”POST /spin.v1.AdminService/ListUsers
List all users
Request
| Field | Type | What it is |
|---|---|---|
page | PageRequest | |
query | string | Optional: filter by name or email |
adminsOnly | boolean | Optional: only return admin users |
Response
| Field | Type | What it is |
|---|---|---|
users | list of User | |
page | PageResponse |
PublishVSCodeServers
Section titled “PublishVSCodeServers”POST /spin.v1.AdminService/PublishVSCodeServers
Publish the servers of the newest stable VS Code releases, or of the commits named, as a new release. Answers once the publish has begun - it downloads a gigabyte - and GetVSCodeServers says how it goes.
Request
| Field | Type | What it is |
|---|---|---|
newest | integer (int32) | The newest stable releases to carry: 2 is the current one and the one before it. |
commits | list of string | Commits to carry besides, each the second line of code --version. |
Response
No fields: {}.
RekeyVolume
Section titled “RekeyVolume”POST /spin.v1.AdminService/RekeyVolume
Re-key a workspace’s disk: copy it whole under a key of its own, point the workspace at the copy, and delete the disk - which shreds the key assumed taken and every snapshot of the disk, since those are what that key opens. The workspace must be stopped or quarantined. Refused for a disk something descends from. Audited.
Request
| Field | Type | What it is |
|---|---|---|
workspaceId | string |
Response
| Field | Type | What it is |
|---|---|---|
targetVolumeId | string |
RemoveAllowedEmail
Section titled “RemoveAllowedEmail”POST /spin.v1.AdminService/RemoveAllowedEmail
Remove allowed email/domain
Request
| Field | Type | What it is |
|---|---|---|
id | string |
Response
No fields: {}.
RemoveStoredVolume
Section titled “RemoveStoredVolume”POST /spin.v1.AdminService/RemoveStoredVolume
Remove an image, an extension release, an unclaimed volume or an orphan from the store: its row, then its volume, whose key is shredded; storage-gc collects its layers on its next run. Refused for one that is kept (StoredVolume.kept_because), one placed on a host, and a workspace’s disk. Audited.
Request
| Field | Type | What it is |
|---|---|---|
volumeId | string |
Response
No fields: {}.
RetryPlatformImages
Section titled “RetryPlatformImages”POST /spin.v1.AdminService/RetryPlatformImages
Look again now rather than when the next retry is due.
Request
No fields: {}.
Response
No fields: {}.
RevokeUserAPIKey
Section titled “RevokeUserAPIKey”POST /spin.v1.AdminService/RevokeUserAPIKey
Revoke another user’s API key - the offboarding an admin cannot do by asking the user, who may already be gone. It is audited with the admin who did it.
Request
| Field | Type | What it is |
|---|---|---|
userId | string | |
id | string |
Response
No fields: {}.
RunJobNow
Section titled “RunJobNow”POST /spin.v1.AdminService/RunJobNow
Run a job now rather than when it is next due. Refused while it is running: a second run alongside the first would do the same work twice. Audited with the admin who asked.
Request
| Field | Type | What it is |
|---|---|---|
job | string |
Response
No fields: {}.
SetRegistrationMode
Section titled “SetRegistrationMode”POST /spin.v1.AdminService/SetRegistrationMode
Set registration mode
Request
| Field | Type | What it is |
|---|---|---|
mode | RegistrationMode |
Response
| Field | Type | What it is |
|---|---|---|
mode | RegistrationMode |
UntagImage
Section titled “UntagImage”POST /spin.v1.AdminService/UntagImage
Take a ref off what it names: no new workspace gets those bytes by it, the disks cloned from them go on reading them, and a later publish under the ref tags the new bytes. Audited.
Request
| Field | Type | What it is |
|---|---|---|
ref | string |
Response
No fields: {}.
UpdateInstallationSettings
Section titled “UpdateInstallationSettings”POST /spin.v1.AdminService/UpdateInstallationSettings
Update installation settings
Request
| Field | Type | What it is |
|---|---|---|
settings | InstallationSettings | |
updateMask | FieldMask | Required: only the named fields of settings are written, so a form that edits one setting cannot reset the others to their zero values. |
Response
| Field | Type | What it is |
|---|---|---|
settings | InstallationSettings |
UpdateNetworkPolicy
Section titled “UpdateNetworkPolicy”POST /spin.v1.AdminService/UpdateNetworkPolicy
Request
| Field | Type | What it is |
|---|---|---|
policy | NetworkPolicyRule |
Response
No fields: {}.
UpdateResourcePreset
Section titled “UpdateResourcePreset”POST /spin.v1.AdminService/UpdateResourcePreset
Update a resource preset
Request
| Field | Type | What it is |
|---|---|---|
id | string | Required: preset ID to update |
name | string | Optional: new display name |
description | string | Optional: new description |
cpuCores | integer (int32) | Optional: new CPU cores |
memoryMb | integer (int32) | Optional: new memory |
diskGb | integer (int32) | Optional: new disk |
burst | BurstMode | Optional: new burst mode |
isDefault | boolean | Optional: make this the default |
enabled | boolean | Optional: enable/disable |
sortOrder | integer (int32) | Optional: new display order |
burstFloorCpuCores | integer (int32) | Optional: new burst floor |
burstFloorMemoryMb | integer (int32) | Optional: new burst floor |
bandwidthMbps | integer or null (int32) | Optional: a new bandwidth. Present, since zero - unshaped - is an answer and not “keep”. |
rpoSeconds | integer or null (int32) | Optional: a new RPO. Present, since zero - the installation’s - is an answer and not “keep”. |
Response
| Field | Type | What it is |
|---|---|---|
preset | ResourcePreset |
UpdateSecuritySettings
Section titled “UpdateSecuritySettings”POST /spin.v1.AdminService/UpdateSecuritySettings
Update security settings
Request
| Field | Type | What it is |
|---|---|---|
settings | SecuritySettings |
Response
| Field | Type | What it is |
|---|---|---|
settings | SecuritySettings |
UpdateStorageSettings
Section titled “UpdateStorageSettings”POST /spin.v1.AdminService/UpdateStorageSettings
Set where the object store is, checked against it before it is written; every control plane restarts within seconds to open it. Another store while volumes exist is refused.
Request
| Field | Type | What it is |
|---|---|---|
bucket | string | |
endpoint | string | |
region | string | |
accessKeyId | string | |
secretAccessKey | string or null | Absent keeps the secret there is. |
dir | string | |
principal | string |
Response
| Field | Type | What it is |
|---|---|---|
settings | StorageSettings |
UpdateUser
Section titled “UpdateUser”POST /spin.v1.AdminService/UpdateUser
Update user (can toggle is_instance_admin, disable user)
Request
| Field | Type | What it is |
|---|---|---|
id | string | Required: user ID |
isInstanceAdmin | boolean or null | Toggle admin status |
disabled | boolean or null | Disable/enable user |
disabledReason | string or null | Reason for disabling (shown to user) |
Response
| Field | Type | What it is |
|---|---|---|
user | User |
Generated by task reference from spin/internal/controlplane/apidocs/spin.v1.openapi.json at 8eee32b9d.
Documents Spinbox v20261019.02. This page as Markdown, for a model or a terminal.

