Skip to content

Terminate an instance (async; soft-deleted for 7d). Refused while `terminationProtection` is set.

POST
/v1/projects/{projectId}/compute/instances/{instanceId}/actions/terminate
Code sample: Shell / cURL
curl --request POST \
--url https://stratum.example.com/v1/projects/example/compute/instances/example/actions/terminate \
--header 'Authorization: Bearer <token>'

Async deletion — flips the instance into terminating; the worker reconciles it to terminated (soft-deleted, retained 7d for audit). Legal from creating, running, stopped, and error. Terminating from creating cancels an in-flight launch — a row wedged behind a bad image or an IPAM stall — without the force escape hatch. The genuinely-wedged transitional states (stopping, starting, rebooting, migrating) have no legal terminating edge and return 409 INVALID_STATE; use force-terminate for those.

projectId
required
string
/^p-[a-z0-9-]+$/
instanceId
required
string
/^i-[a-z0-9-]+$/

Reconciliation in progress.

Media typeapplication/json
object
id
required
string
/^i-[a-z0-9-]+$/
projectId
required
string
/^p-[a-z0-9-]+$/
name
required
string
displayName
string
description
string
instanceType

Catalog name (e.g. m1.large); references the instance-type catalog. Empty for custom-shape launches — read vcpus + memoryBytes for the effective shape in that case.

string
vcpus
required

Effective vCPU count. Populated for every instance mirrors the catalog entry for catalog launches; carries the operator’s override for custom-shape launches.

integer
>= 1
memoryBytes
required

Effective memory in bytes. Populated for every instance (catalog or custom).

integer format: int64
>= 1048576
imageId
required
string
/^img-[a-z0-9-]+$/
region
required
string
availabilityZone
required
string
hypervisorNodeId

Empty until the scheduler stamps it.

string
/^n-[a-z0-9-]+$/
state
required

customer-visible state.

string
Allowed values: creating starting running stopping stopped rebooting migrating terminating terminated error
stateReason

Human-readable detail set when state=error.

string
health

aggregated, read-time instance-health roll-up, derived from durable signals (lifecycle state + agent heartbeat recency). healthy: running, agent heartbeating. degraded: running and heartbeating but the host can’t read a fresh domain sample (or vice-versa). unhealthy: running with no agent heartbeat, or state=error. migrating: a cold migration is in flight. unknown: transitional or deliberately-down states where the lifecycle state itself is the signal, and an agent enabled after launch whose install command has not been run yet. agent_disabled: agentEnabled: false, at launch or since, so the agent’s absence is the configured intent, not a fault — distinct from unhealthy precisely so an appliance image or an operator who declined the agent does not read as broken forever. Stable across a control-plane restart (the in-memory session channel is not an input).

string
Allowed values: healthy degraded unhealthy migrating unknown agent_disabled
healthReason

Why health reads the way it does. Present only on the describe path (GET-by-id), and only when health needs explaining; omitted for a healthy instance.

Read this before acting on health: unhealthy: it is what separates an agent that never arrived (permanent — rebuild) from one that has merely gone quiet (often self-resolving), and it carries the first-heartbeat deadline so a normal launch is not mistaken for a broken one.

object
code
required

Machine-readable cause.

agent_pending: running, no heartbeat yet, still inside the first-heartbeat grace window. health already reads unhealthy (it flips within ~3 minutes), so this is what distinguishes a perfectly normal launch from a broken one — see deadline.

agent_never_reported: past the grace window having never reported. Permanent without intervention; run enable-agent for a new install command, or disable-agent if the instance is not meant to have an agent.

agent_gone_quiet: reported at least once and then stopped. The agent was installed correctly, so this is not a delivery bug; frequently self-resolving.

agent_disabled: agentEnabled: false, declined at launch or disabled since. Not a fault — reported rather than omitted so a reader who expected an agent learns why there is none instead of hunting a failure that never happened.

agent_enrollment_pending: enable-agent ran and its install command has not been run in the guest yet. health reads unknown; nothing has failed.

string
Allowed values: agent_pending agent_never_reported agent_gone_quiet agent_disabled agent_enrollment_pending
message
required

Human-readable explanation, including what to do about it. Not a stable contract — switch on code.

string
since

When the reported condition began — launch (or enrollment, for an agent added later) for an agent that never reported, the last heartbeat for one that has gone quiet.

string format: date-time
deadline

When a pending agent stops being given the benefit of the doubt. Set only for agent_pending; after this the code becomes agent_never_reported.

string format: date-time
agentEnabled

Whether the instance is meant to run the in-VM Stratum agent. Set at create (CreateInstanceRequest.agentEnabled); changed later only by the enable-agent and disable-agent actions.

False means the agent is not wanted, so health reports agent_disabled rather than unhealthy and the instance is excluded from agent-presence reconciliation. Read this before concluding an instance is broken because it never reported.

boolean
agentEnrollmentPending

enable-agent ran and its install command has not been run in the guest yet. health reads unknown (reason agent_enrollment_pending) until it is.

boolean
agentEnrolledAt

When an enable-agent install command last enrolled the agent, or, with agentActivation: automatic, when enable-agent turned it on. Absent for an agent installed at launch. The first-heartbeat grace window runs from here rather than from launchedAt.

string format: date-time
agentActivation

How the agent is turned on in the guest after launch, fixed at launch from the image the instance launched from. It changes once at most: enable-agent with force: true turns automatic into install-command for good, for a guest whose dormant package was removed.

automatic: the image ships the agent installed but dormant, with a timer that follows the agent flag. enable-agent and disable-agent take effect in the guest within a minute, with nothing to run there, and disabling keeps the package installed.

install-command: any other image. enable-agent returns a one-time install command to run in the guest, and disable-agent removes the agent.

Images created from the instance (create-image, image builder output) carry the stratum.dev/agent-activation: automatic tag only while it reads automatic.

string
Allowed values: automatic install-command
agentStatus

In-VM agent liveness, embedded on the instance describe (GET-by-id) response so a detail view has agent health without a second round-trip to .../agent-status. Present only on the describe path; omitted on list and the action responses. An instance whose agent has never reported carries health: unknown.

object
instanceId
required
string
health
required

Derived agent liveness. agent_disabled: the instance’s agentEnabled is false, so no agent is wanted and its silence is not a fault. enrollment_pending: enable-agent ran and its install command has not been run in the guest yet. Exactly the instance fields, so the two never disagree.

string
Allowed values: healthy unhealthy unknown agent_disabled enrollment_pending
lastSeen

When the control plane last received a heartbeat.

string format: date-time
agentVersion

The agent’s reported build version.

string
lastReconcileResult

Result of the agent’s most recent reconcile (“ok” or “error”).

string
lastReconcileAt

When the agent last completed a reconcile.

string format: date-time
rootVolumeId
required
string
/^vol-[a-z0-9-]+$/
rootVolumeAutoProvisioned

True when the root volume was auto-provisioned by CreateInstance and is cleaned up on terminate.

boolean
additionalVolumes
Array<object>
object
volumeId
required
string
/^vol-[a-z0-9-]+$/
deviceName
required

Guest device path (e.g. /dev/vdb).

string
deleteOnTermination
required
boolean
deviceIndex

Set when the launch cloned this volume from a multi-volume image’s data device.

integer
snapshotId

The image snapshot this volume was cloned from at launch.

string
primaryNicId

Primary network interface ID. Set by the launch path when SubnetIDs are supplied or the project’s default subnet is resolved.

string
/^nic-[a-z0-9-]+$/
primaryNicAutoProvisioned

True when the primary NIC was auto-provisioned by CreateInstance and is cleaned up on terminate.

boolean
primaryFipId

Floating IP attached to the primary NIC, when one was allocated at launch via floatingIPPool / –public-ip.

string
/^fip-[a-z0-9-]+$/
primaryFipAutoProvisioned

True when the primary FIP was auto-allocated by CreateInstance and is released on terminate.

boolean
networkInterfaces
Array<object>
object
nicId
required
string
/^nic-[a-z0-9-]+$/
deviceIndex
required
integer
primary
required
boolean
privateIp

The NIC’s primary private IPv4 address within its subnet. Empty until the NIC is scheduled onto a subnet and an address is assigned (e.g. while the instance is still creating).

string
subnetId

The subnet this NIC actually landed in, enriched at read time from the network NIC row. Nothing on the instance reported placement before. A create request naming subnetId instead of the real subnetIds had the field silently dropped, returned 201, and attached the NIC to the default platform network — with no response field distinguishing that from a correctly placed instance.

string
vpcId

The VPC the NIC’s subnet belongs to.

string
primaryPrivateIP
string
privateIp

AWS-parity alias of primaryPrivateIP.

string
primaryPublicIP
string
publicDnsName

The instance’s public DNS name, <instance-id>.compute.<parent> (the AWS PublicDnsName). The install’s authoritative DNS answers it with primaryPublicIP, and with the private IP when asked from inside the instance’s own VPC.

Set while that record is published: the instance has a floating IP on its primary NIC, its VPC has dnsHostnames on, and the install has a DNS parent domain. Omitted otherwise. The record follows within one reconciler pass (30 s) of the floating IP being associated or the VPC setting changing. The same name IMDS serves at meta-data/public-hostname.

For a name of your own, create an alias record in a hosted zone. An aliasTarget of type: fip answers the floating IP’s address; one of type: instance answers the instance’s private IP and publishes a public.<name> companion for its floating IP. Both follow the address as it changes.

string
keyPairName
string
placementGroupId

The placement group this instance was placed by. Absent when it joined none.

It can become absent without the instance changing: deleting a group leaves its members running and drops the reference. That is losing the guarantee, not moving between groups.

string
/^pg-[a-z0-9-]+$/
placementGroupName

Name of the placement group this instance was placed by — what the tenant declared at launch. Absent when it joined none, and absent alongside placementGroupId once the group is deleted.

string
userDataHash

SHA-256 over the user-data bytes, sha256:<hex>.

string
iamRoleArn

Reserved for instance profiles (/ 2.x).

string
iamInstanceProfileId

Attached instance profile. Apps inside the VM that hit IMDS get short-lived credentials for the profile’s service account. Empty when no profile is attached.

string
/^iprof-[a-z0-9]+$/
tags
object
key
additional properties
string
stopProtection
required
boolean
terminationProtection
required
boolean
autostart

When true the controlplane queues a start lifecycle action against this instance on boot if libvirt currently has the domain shut off. Default false.

boolean
desiredState

The power state the operator has ASKED for, as distinct from state, which is what the instance actually is. A leader-gated reconciler converges the two, so setting this returns immediately rather than blocking for a guest shutdown.

They are separate fields deliberately: collapsing them would make “someone stopped this by hand” indistinguishable from “this is meant to be stopped”. An instance manually stopped while desiredState=running is started again on the next pass.

Only running and stopped are accepted. starting/stopping are transitions the worker owns and are never a destination.

string
default: running
Allowed values: running stopped
stopForce

True while a stop asked with force: true (a hard stop, the Multi-AZ fence) is in flight; cleared when the instance leaves stopping.

boolean
metadataOptions

Per-instance AWS-shape IMDS options. Returned on the Instance and settable at launch (CreateInstanceRequest) or via the modify-metadata-options action. httpEndpoint is enforced: when disabled the whole IMDS surface (including the Stratum SSH-CA agent plane) is off for the instance. httpTokens + httpPutResponseHopLimit are recorded for AWS parity only — Stratum’s IMDS always requires a session token (effectively IMDSv2-only), so optional does not relax that in v1. Omitted fields default to enabled / required / 1.

object
httpEndpoint

Whether IMDS is reachable for the instance. Default enabled.

string
Allowed values: enabled disabled
httpTokens

IMDSv2 token requirement (recorded; Stratum is always v2). Default required.

string
Allowed values: optional required
httpPutResponseHopLimit

Recorded for AWS parity. Default 1.

integer
>= 1 <= 64
instanceMetadataTags

When enabled the guest can read its own tags at /latest/meta-data/tags/instance/. Default disabled; the image builder enables it on a build instance.

string
Allowed values: enabled disabled
createdAt
required
string format: date-time
launchedAt
string format: date-time
updatedAt
required
string format: date-time
terminatedAt
string format: date-time
createdBy
required
string

Example

{
"state": "creating",
"health": "healthy",
"healthReason": {
"code": "agent_pending",
"message": "the agent has NEVER checked in, 4 days after it was installed — it was not installed, or it cannot reach IMDS. This will NOT resolve on its own and no retry is scheduled: run enable-agent for a new install command and run it in the guest, or disable the agent if the instance is not meant to have one."
},
"agentActivation": "automatic",
"agentStatus": {
"instanceId": "i-A8c2D4e6F",
"health": "healthy"
},
"networkInterfaces": [
{
"privateIp": "172.31.0.42",
"subnetId": "subnet-6arpymeu32",
"vpcId": "vpc-puhtjesijq"
}
],
"desiredState": "running",
"metadataOptions": {
"httpEndpoint": "enabled",
"httpTokens": "optional",
"instanceMetadataTags": "enabled"
}
}

Termination protection is enabled, or the instance is in a transitional state with no legal terminating edge (use force-terminate).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
>= 400 <= 599
detail
string
instance
string format: uri-reference
requestId
required
string
code
required
string
issues

The findings of a rejected IAM policy document (custom and resource policies).

Array<object>

One finding of a rejected IAM policy document. A rejection lists every finding, so the author fixes the document in one round trip.

object
code
required

The finding, e.g. INVALID_DOCUMENT, UNKNOWN_ACTION, ACTION_NOT_APPLICABLE.

string
statement
required

Index of the statement at fault; -1 for the document as a whole.

integer
>= -1
detail
required
string
action

The offending action, where one is at fault (ACTION_NOT_APPLICABLE).

string
errors

Field errors, for codes that carry them: each problem at its field (see FieldError). Documented on the responses that set it, e.g. approveNodeJoin’s INVALID_INPUT and JOIN_APPROVAL_REFUSED. Absent otherwise.

Array<object>

One field’s problem, the stage-2 installer API’s shape. field is the field’s path, message what is wrong with it.

object
field
required

The field’s path, e.g. links[0].interface, disks[1].confirm, mgmt.address or role; empty for the whole request.

string
message
required
string
details

Structured facts about the refusal, for codes that carry them. The shape is fixed per code and documented on the response that answers it, e.g. IMAGE_POOL_MISMATCH (see ImagePoolMismatchDetails) and IMAGE_IN_USE. Absent for codes that carry none.

object
key
additional properties
any

Example

{
"issues": [
{
"code": "ACTION_NOT_APPLICABLE",
"action": "compute:CreateVpc"
}
]
}