# Core endpoints (Client API: VDS)

> 26 FeatherPanel Client API: VDS endpoints from user/vds/core.php: methods, paths, auth, permissions, rate limits, parameters and responses.

Source: https://featherpanel.com/docs/api/reference/user/vds/core/

Defined in [`backend/app/routes/user/vds/core.php`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php). Authentication used here: **Signed-in user**, **VDS access**. Read [Authentication](https://featherpanel.com/docs/api/authentication/) for how to send credentials and [Rate limits and errors](https://featherpanel.com/docs/api/rate-limits-and-errors/) for the response envelope.

Paths, methods, permissions and rate limits come from the route file. Summaries, parameters and response codes come from the OpenAPI annotations on the controllers; endpoints without annotations show only what the route file declares.

## Endpoints

### GET `/api/user/vm-instances`

- Auth: Signed-in user
- Default rate limit: 2 / second (`user-vm-instances`)
- Route name: `user-vm-instances`
- Controller: [`VmUserInstanceController::getUserVmInstances`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L28)

**List user VM instances** Get VM instances owned by or accessible to the authenticated user. Supports optional pagination and search.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `page` | query | integer | no | Page number |
| `limit` | query | integer | no | Records per page |
| `search` | query | string | no | Search by hostname or IP |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `instances` | object\[\] |  |
| `pagination` | object |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` VM instances retrieved successfully · `401` Unauthorized

### GET `/api/user/vm-instances/{id}`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-get`
- Controller: [`VmUserInstanceController::getVmInstance`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L40)

**Get VM instance details** Get detailed information about a specific VM instance.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `instance` | object |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` VM instance retrieved successfully · `401` Unauthorized · `403` Forbidden · `404` VM instance not found

### GET `/api/user/vm-instances/{id}/status`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-status`
- Controller: [`VmUserInstanceController::getVmInstanceStatus`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L57)

**Get VM instance status** Get current status and resource usage from Proxmox.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `status` | object |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/status" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Status retrieved successfully · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Proxmox error

### GET `/api/user/vm-instances/{id}/qemu-hardware`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-qemu-hardware-get`
- Controller: [`VmUserInstanceController::getQemuHardware`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L75)

**Get QEMU hardware settings (EFI + TPM + Serial)** Returns the current QEMU BIOS mode and whether EFI disk, TPM state disk, and serial0 socket are enabled.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `bios` | string |  |
| `efi_enabled` | boolean |  |
| `tpm_enabled` | boolean |  |
| `serial0_enabled` | boolean |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/qemu-hardware" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Hardware settings fetched successfully · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Internal server error · `503` Proxmox error

### PATCH `/api/user/vm-instances/{id}/qemu-hardware`

- Auth: VDS access
- Default rate limit: 10 / minute
- Route name: `user-vm-instance-qemu-hardware-patch`
- Controller: [`VmUserInstanceController::patchQemuHardware`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L92)

**Update QEMU hardware settings (EFI + TPM + Serial)** Updates Proxmox config to enable/disable EFI disk, TPM state disk, and serial0 socket. Optional BIOS mode can be updated.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `bios` | string | no |  |
| `efi_enabled` | boolean | no |  |
| `tpm_enabled` | boolean | no |  |
| `serial0_enabled` | boolean | no |  |

```bash
curl -X PATCH "$PANEL_URL/api/user/vm-instances/$ID/qemu-hardware" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"bios":"","efi_enabled":false,"tpm_enabled":false,"serial0_enabled":false}'
```

Plugin events: [`featherpanel:vds:qemu:hardware:update`](https://featherpanel.com/docs/plugins/events/vds/#vds-qemu-hardware-updated)

Responses: `200` Hardware updated successfully · `400` Bad request · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Internal server error · `503` Proxmox error

### GET `/api/user/vm-instances/{id}/network-options`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-network-options`
- Controller: [`VmUserInstanceController::getNetworkOptions`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L110)

**Get DNS options** Returns current DNS settings (nameserver/searchdomain). Supports both QEMU and LXC.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `nameserver` | string |  |
| `searchdomain` | string |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/network-options" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Options fetched successfully · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Internal server error · `503` Proxmox error

### GET `/api/user/vm-instances/{id}/networking`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-networking`
- Controller: [`VmUserInstanceController::getNetworking`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L127)

**Get VM networking details** Returns assigned IP addresses and current DNS settings for a VDS instance.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/networking" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Networking details fetched · `401` Unauthorized · `403` Forbidden · `404` VM instance not found

### PATCH `/api/user/vm-instances/{id}/network-dns`

- Auth: VDS access
- Default rate limit: 10 / minute
- Route name: `user-vm-instance-network-dns-patch`
- Controller: [`VmUserInstanceController::patchNetworkDns`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L144)

**Update DNS settings** Updates nameserver (and searchdomain for LXC). Primary IP is intentionally not editable for normal users.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `nameserver` | string | no |  |
| `searchdomain` | string | no |  |

```bash
curl -X PATCH "$PANEL_URL/api/user/vm-instances/$ID/network-dns" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"nameserver":"","searchdomain":""}'
```

Plugin events: [`featherpanel:vds:network:update`](https://featherpanel.com/docs/plugins/events/vds/#vds-network-updated)

Responses: `200` Updated successfully · `400` Bad request · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Internal server error · `503` Proxmox error

### GET `/api/user/vm-instances/{id}/iso-storages`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-iso-storages`
- Controller: [`VmUserInstanceController::getIsoStorages`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L162)

**List ISO storages** Returns ISO-capable Proxmox storage names for the VM node.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `storages` | string\[\] |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/iso-storages" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` ISO storages fetched · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Internal server error · `503` Proxmox error

### GET `/api/user/vm-instances/{id}/iso-current`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-iso-current`
- Controller: [`VmUserInstanceController::getIsoCurrent`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L179)

**Get currently mounted ISO** Returns currently mounted ISO (if any) by inspecting QEMU cdrom devices (media=cdrom).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/iso-current" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` ISO current fetched · `400` Bad request · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Internal server error · `503` Proxmox error

### POST `/api/user/vm-instances/{id}/iso-upload-and-mount`

- Auth: VDS access
- Default rate limit: 2 / minute
- Route name: `user-vm-instance-iso-upload-and-mount`
- Controller: [`VmUserInstanceController::uploadAndMountIso`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L196)

**Upload and mount an ISO** Uploads an ISO to Proxmox and mounts it as the VM cdrom (ide2) while enforcing only one ISO/cdrom at a time.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `storage` | string | yes | ISO storage name on Proxmox |
| `file` | string (binary) | yes | ISO file to upload |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/iso-upload-and-mount" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -F "storage=" \
  -F "file=@./file"
```

Plugin events: [`featherpanel:vds:iso:mount`](https://featherpanel.com/docs/plugins/events/vds/#vds-iso-mounted)

Responses: `200` Mounted successfully · `400` Bad request · `401` Unauthorized · `403` Forbidden · `500` Internal server error · `503` Proxmox error

### POST `/api/user/vm-instances/{id}/iso-fetch-and-mount`

- Auth: VDS access
- Default rate limit: 2 / minute
- Route name: `user-vm-instance-iso-fetch-and-mount`
- Controller: [`VmUserInstanceController::fetchAndMountIsoFromUrl`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L213)

**Fetch ISO from URL and mount it** Proxmox downloads the ISO directly from a remote URL into the ISO storage, then mounts it as VM cdrom (ide2) while enforcing only one ISO/cdrom at a time.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `storage` | string | no | ISO storage name on Proxmox |
| `url` | string (uri) | no | Remote ISO URL to download |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/iso-fetch-and-mount" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"storage":"","url":""}'
```

Plugin events: [`featherpanel:vds:iso:mount`](https://featherpanel.com/docs/plugins/events/vds/#vds-iso-mounted)

Responses: `200` Mounted successfully · `400` Bad request · `401` Unauthorized · `403` Forbidden · `500` Internal server error · `503` Proxmox error

### POST `/api/user/vm-instances/{id}/iso-unmount`

- Auth: VDS access
- Default rate limit: 5 / minute
- Route name: `user-vm-instance-iso-unmount`
- Controller: [`VmUserInstanceController::unmountIso`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L230)

**Unmount ISO** Unlinks cdrom devices (media=cdrom) and sets VM boot order back to the main disk.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/iso-unmount" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Plugin events: [`featherpanel:vds:iso:unmount`](https://featherpanel.com/docs/plugins/events/vds/#vds-iso-unmounted)

Responses: `200` Unmounted successfully · `400` Bad request · `401` Unauthorized · `403` Forbidden · `500` Internal server error · `503` Proxmox error

### GET `/api/user/vm-instances/{id}/templates`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-templates`
- Controller: [`VmUserInstanceController::getTemplates`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L247)

**Get available templates** Get available templates for the VM instance to reinstall. Limited to the VM type (qemu/lxc).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `templates` | object\[\] |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/templates" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Templates retrieved successfully · `401` Unauthorized · `403` Forbidden · `404` VM instance not found

### POST `/api/user/vm-instances/{id}/power`

- Auth: VDS access
- Default rate limit: 10 / minute
- Route name: `user-vm-instance-power`
- Controller: [`VmUserInstanceController::powerAction`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L264)

**VM power action** Perform power action: start, stop, or reboot.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `action` | string | no |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `instance` | object |  |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/power" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"action":""}'
```

Plugin events: [`featherpanel:vds:power:action`](https://featherpanel.com/docs/plugins/events/vds/#vds-power-action)

Responses: `200` Power action completed · `400` Bad request · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` Power action failed

### GET `/api/user/vm-instances/{id}/vnc-ticket`

- Auth: VDS access
- Default rate limit: 10 / minute
- Route name: `user-vm-instance-vnc`
- Controller: [`VmUserInstanceController::getVncTicket`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L281)

**Get VNC console ticket** Get VNC console access ticket. Returns wss\_url (and optionally pve\_redirect\_url when panel can create a short-lived PVE user).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `ticket` | string |  |
| `port` | integer |  |
| `node` | string |  |
| `vmid` | integer |  |
| `host` | string |  |
| `port_api` | integer |  |
| `wss_url` | string |  |
| `pve_redirect_url` | string | Proxmox noVNC URL when available |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/vnc-ticket" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Plugin events: [`featherpanel:vds:console:access`](https://featherpanel.com/docs/plugins/events/vds/#vds-console-accessed)

Responses: `200` VNC ticket created · `401` Unauthorized · `403` Forbidden · `404` VM instance not found · `500` VNC proxy failed

### POST `/api/user/vm-instances/{id}/reinstall`

- Auth: VDS access
- Default rate limit: 5 / minute
- Route name: `user-vm-instance-reinstall`
- Controller: [`VmUserInstanceController::reinstall`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L298)

**Start async VM reinstall** Starts a full reinstall by cloning from the instance template. Returns 202 with reinstall\_id. Poll GET /api/user/vm-instances/reinstall-status/{reinstallId} until status is active or failed. For QEMU/KVM, send ci\_user and ci\_password in the request body.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes | VM instance ID |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `ci_user` | string | no | Cloud-init username (required for QEMU/KVM) |
| `ci_password` | string | no | Cloud-init password (required for QEMU/KVM) |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `reinstall_id` | string |  |
| `message` | string |  |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/reinstall" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"ci_user":"","ci_password":""}'
```

Plugin events: [`featherpanel:vds:reinstall`](https://featherpanel.com/docs/plugins/events/vds/#vds-reinstalled)

Responses: `202` Reinstall started · `400` Bad request (e.g. missing ci\_user/ci\_password for QEMU) · `401` Unauthorized · `403` Forbidden · `404` VM or template not found · `500` Server error

### GET `/api/user/vm-instances/reinstall-status/{reinstallId}`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-vm-instances`)
- Route name: `user-vm-instance-reinstall-status`
- Controller: [`VmUserInstanceController::reinstallStatus`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L315)

**Poll reinstall status** Poll until status is active or failed. Use the reinstall\_id returned from POST .../reinstall. Returns status: cloning (keep polling), failed (with error), or active (with instance).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `reinstallId` | path | string | yes | Reinstall ID from start reinstall response |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `status` | string |  |
| `message` | string | When status=cloning |
| `error` | string | When status=failed |
| `instance` | object | When status=active |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/reinstall-status/$REINSTALL_ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Status (cloning | failed | active) · `400` Missing reinstall\_id · `401` Unauthorized · `404` Reinstall not found or access denied · `500` Server error

### GET `/api/user/vm-instances/task-status/{taskId}`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-vm-instances`)
- Route name: `user-vm-instance-task-status`
- Controller: [`VmUserInstanceController::taskStatus`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserInstanceController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L329)

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `taskId` | path | \- | yes |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/task-status/$TASK_ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

### GET `/api/user/vm-instances/{id}/backups`

- Auth: VDS access
- Default rate limit: 30 / minute
- Route name: `user-vm-instance-backups-list`
- Controller: [`VmUserBackupController::listBackups`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L343)

**List VM backups** List backups for this VM instance. Returns backups, backup\_limit (max allowed), and available Proxmox storages. Respects instance backup limit.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes | VM instance ID |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `backups` | object\[\] |  |
| `backup_limit` | integer | Max backups allowed for this instance |
| `storages` | string\[\] | Available backup storages on node |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/$ID/backups" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Backups listed · `401` Unauthorized · `403` Forbidden · `404` VM instance not found

### POST `/api/user/vm-instances/{id}/backups/{backupId}/recover`

- Auth: VDS access
- Default rate limit: 5 / minute
- Route name: `user-vm-instance-backup-recover`
- Controller: [`VmUserBackupController::recoverBackup`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L360)

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | \- | yes |  |
| `backupId` | path | \- | yes |  |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/backups/$BACKUP_ID/recover" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

### POST `/api/user/vm-instances/{id}/backups`

- Auth: VDS access
- Default rate limit: 10 / minute
- Route name: `user-vm-instance-backup-create`
- Controller: [`VmUserBackupController::createBackup`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L372)

**Create VM backup** Start an async vzdump backup. Returns 202 with backup\_id. Poll GET /api/user/vm-instances/backup-status/{backupId} until status is done or failed. Fails with 422 if backup limit reached.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `storage` | string | no | Proxmox storage (optional) |
| `compress` | string | no |  |
| `mode` | string | no |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `backup_id` | string |  |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/backups" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"storage":"","compress":"","mode":""}'
```

Plugin events: [`featherpanel:vds:backup:create`](https://featherpanel.com/docs/plugins/events/vds/#vds-backup-created)

Responses: `202` Backup started · `400` Bad request · `401` Unauthorized · `403` Forbidden · `404` VM not found · `422` Backup limit reached · `500` Proxmox error

### GET `/api/user/vm-instances/backup-status/{backupId}`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-vm-instances`)
- Route name: `user-vm-instance-backup-status`
- Controller: [`VmUserBackupController::backupStatus`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L389)

**Poll backup status** Poll until status is done or failed. Use backup\_id from create backup response.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `backupId` | path | string | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `status` | string |  |
| `error` | string |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/backup-status/$BACKUP_ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Status (running | done | failed) · `400` Invalid task · `401` Unauthorized · `404` Not found or access denied

### DELETE `/api/user/vm-instances/{id}/backups`

- Auth: VDS access
- Default rate limit: 10 / minute
- Route name: `user-vm-instance-backup-delete`
- Controller: [`VmUserBackupController::deleteBackup`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L403)

**Delete VM backup** Delete a backup volume. Request body: volid and storage (from list backups).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `volid` | string | yes |  |
| `storage` | string | yes |  |

```bash
curl -X DELETE "$PANEL_URL/api/user/vm-instances/$ID/backups" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"volid":"","storage":""}'
```

Plugin events: [`featherpanel:vds:backup:delete`](https://featherpanel.com/docs/plugins/events/vds/#vds-backup-deleted)

Responses: `200` Backup deleted · `400` Missing volid or storage · `401` Unauthorized · `403` Forbidden or backup does not belong to this VM · `404` VM not found

### POST `/api/user/vm-instances/{id}/backups/restore`

- Auth: VDS access
- Default rate limit: 5 / minute
- Route name: `user-vm-instance-restore-backup`
- Controller: [`VmUserBackupController::restoreBackup`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L420)

**Restore VM from backup** Start async restore from a backup. Returns 202 with restore\_id. Poll GET /api/user/vm-instances/restore-status/{restoreId} until status is active or failed.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes |  |

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `volid` | string | yes |  |
| `storage` | string | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `restore_id` | string |  |

```bash
curl -X POST "$PANEL_URL/api/user/vm-instances/$ID/backups/restore" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"volid":"","storage":""}'
```

Plugin events: [`featherpanel:vds:backup:restore`](https://featherpanel.com/docs/plugins/events/vds/#vds-backup-restored)

Responses: `202` Restore started · `400` Missing volid or storage · `401` Unauthorized · `403` Forbidden · `404` VM not found · `500` Proxmox error

### GET `/api/user/vm-instances/restore-status/{restoreId}`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-vm-instances`)
- Route name: `user-vm-instance-restore-status`
- Controller: [`VmUserBackupController::restoreBackupStatus`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/Vds/VmUserBackupController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/vds/core.php#L437)

**Poll restore status** Poll until status is active or failed. Use restore\_id from restore backup response.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `restoreId` | path | string | yes |  |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `status` | string |  |
| `instance` | object |  |
| `error` | string |  |

```bash
curl -X GET "$PANEL_URL/api/user/vm-instances/restore-status/$RESTORE_ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Status (restoring | active | failed) · `400` Invalid task · `401` Unauthorized · `404` Not found or access denied
