> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phala.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CVM Lifecycle

> Provision, start, stop, restart, delete, and replicate CVMs using the Python SDK.

CVM lifecycle methods control the creation and state transitions of your Confidential Virtual Machines. Provisioning is a two-step process (provision then commit), while other operations are single calls.

## CVM Identifiers

Most lifecycle methods accept a CVM identifier. You can pass any of these fields — the SDK resolves them automatically:

| Field | Description |
| - | - |
| `id` | CVM ID (most common) |
| `app_id` | App ID associated with the CVM |
| `uuid` | CVM UUID |
| `instance_id` | Instance ID |
| `cvm_id` | Alias for `id` |

```python theme={"system"}
# All equivalent
client.get_cvm_info({"id": "my-app"})
client.get_cvm_info({"app_id": "my-app"})
client.get_cvm_info({"cvm_id": "my-app"})
```

***

## provision\_cvm

`POST /cvms/provision`

Creates a CVM provision request. This is step one of the two-step provisioning flow. The response includes a `compose_hash` that you use in `commit_cvm_provision`.

**Parameters:**

The request is a dictionary with the CVM configuration. The exact fields depend on your deployment, but typically include:

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | `str` | Yes | CVM display name |
| `compose_file` | `dict` | Yes | Docker Compose configuration |
| `vcpu` | `int` | No | Number of vCPUs |
| `memory` | `int` | No | Memory in MB |
| `disk_size` | `int` | No | Disk size in GB |
| `teepod_id` | `int` | No | Target node ID |

**Returns:** Provision response with `compose_hash` and `app_id`.

**Example:**

<CodeGroup>
  ```python Sync theme={"system"}
  result = client.provision_cvm({
      "name": "my-cvm",
      "compose_file": {
          "docker_compose_file": "services:\n  app:\n    image: nginx:latest",
      },
      "vcpu": 2,
      "memory": 2048,
      "disk_size": 20,
      "teepod_id": 3,
  })
  print(result.compose_hash)
  ```

  ```python Async theme={"system"}
  result = await client.provision_cvm({
      "name": "my-cvm",
      "compose_file": {
          "docker_compose_file": "services:\n  app:\n    image: nginx:latest",
      },
      "vcpu": 2,
      "memory": 2048,
      "disk_size": 20,
      "teepod_id": 3,
  })
  print(result.compose_hash)
  ```
</CodeGroup>

***

## commit\_cvm\_provision

`POST /cvms`

Commits a provisioned CVM, creating the actual instance. This is step two of the provisioning flow. Pass the `compose_hash` from the provision step along with on-chain transaction details.

This endpoint is idempotent: submitting the same `app_id` + `compose_hash` again returns the existing CVM. A different `compose_hash` for the same `app_id` raises a `ResourceError` with error code `CVM_APP_ID_CONFLICT`.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `app_id` | `str` | Yes | App ID from provision step |
| `compose_hash` | `str` | Yes | Hash from provision step |
| `transaction_hash` | `str` | Yes | On-chain transaction hash |

**Returns:** Committed CVM details.

**Example:**

<CodeGroup>
  ```python Sync theme={"system"}
  cvm = client.commit_cvm_provision({
      "app_id": "app-123",
      "compose_hash": "0xabc...",
      "transaction_hash": "0xdef...",
  })
  ```

  ```python Async theme={"system"}
  cvm = await client.commit_cvm_provision({
      "app_id": "app-123",
      "compose_hash": "0xabc...",
      "transaction_hash": "0xdef...",
  })
  ```
</CodeGroup>

***

## start\_cvm

`POST /cvms/{cvmId}/start`

Starts a stopped CVM.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | CVM identifier |

**Returns:** CVM action response with updated status.

**Example:**

<CodeGroup>
  ```python Sync theme={"system"}
  result = client.start_cvm({"id": "my-app"})
  print(result.status)  # "starting"
  ```

  ```python Async theme={"system"}
  result = await client.start_cvm({"id": "my-app"})
  print(result.status)
  ```
</CodeGroup>

***

## stop\_cvm

`POST /cvms/{cvmId}/stop`

Force-stops a CVM immediately.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | CVM identifier |

**Returns:** CVM action response with updated status.

***

## shutdown\_cvm

`POST /cvms/{cvmId}/shutdown`

Gracefully shuts down a CVM, allowing containers to stop cleanly. Prefer this over `stop_cvm` unless you need an immediate halt.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | CVM identifier |

**Returns:** CVM action response with updated status.

***

## restart\_cvm

`POST /cvms/{cvmId}/restart`

Restarts a CVM. Supports an optional `force` flag to skip graceful shutdown.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | CVM identifier |
| `force` | `bool` | No | Force restart without graceful shutdown (default: `False`) |

**Returns:** CVM action response with updated status.

**Example:**

<CodeGroup>
  ```python Sync theme={"system"}
  client.restart_cvm({"id": "my-app", "force": True})
  ```

  ```python Async theme={"system"}
  await client.restart_cvm({"id": "my-app", "force": True})
  ```
</CodeGroup>

***

## delete\_cvm

`DELETE /cvms/{cvmId}`

Permanently deletes a CVM and all its data.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | CVM identifier |

**Returns:** `None`

<Warning>
  This action is irreversible. All data associated with the CVM will be permanently deleted.
</Warning>

**Example:**

<CodeGroup>
  ```python Sync theme={"system"}
  client.delete_cvm({"id": "my-app"})
  ```

  ```python Async theme={"system"}
  await client.delete_cvm({"id": "my-app"})
  ```
</CodeGroup>

***

## replicate\_cvm

`POST /cvms/{cvmId}/replicas`

Creates a copy of an existing CVM. The replica shares the same compose configuration but runs as an independent instance.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Source CVM identifier |
| `node_id` | `int` | No | Target node for the replica |

**Returns:** Replicated CVM details.

**Example:**

<CodeGroup>
  ```python Sync theme={"system"}
  replica = client.replicate_cvm({"id": "my-app", "node_id": 5})
  ```

  ```python Async theme={"system"}
  replica = await client.replicate_cvm({"id": "my-app", "node_id": 5})
  ```
</CodeGroup>

***

## watch\_cvm\_state

`GET /cvms/{cvmId}/state` (SSE)

Polls the CVM state via Server-Sent Events until it reaches a target status. This is useful for waiting until a CVM finishes starting or stopping. Only available on the sync client.

**Parameters:**

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | CVM identifier |
| `target` | `str` | Yes | Target state to wait for (e.g., `"Running"`) |
| `interval` | `int` | No | Polling interval in seconds (default: `5`, range: 5-30) |
| `timeout` | `int` | No | Server-side timeout in seconds (default: `300`, range: 10-600) |
| `max_retries` | `int` | No | Maximum retry attempts |
| `retry_delay` | `float` | No | Delay between retries in seconds (default: `5.0`) |

**Returns:** CVM state object when the target state is reached.

**Raises:** `TimeoutError` if max retries exceeded.

**Example:**

```python theme={"system"}
# Start a CVM and wait for it to be running
client.start_cvm({"id": "my-app"})
state = client.watch_cvm_state({
    "id": "my-app",
    "target": "Running",
    "timeout": 120,
    "max_retries": 3,
})
print(state.status)  # "Running"
```

## Related

* [CVM Configuration](/phala-cloud/references/cloud-python-sdk/cvm-configuration) — updating compose files and resources
* [Error Handling](/phala-cloud/references/cloud-python-sdk/error-handling) — handling provisioning errors


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.