Skip to content

Proxmox Python SDK Guide

Welcome to the proxmox-sdk SDK! This is a standalone, production-ready Python SDK for the Proxmox API that works without any FastAPI server.


What is the Proxmox SDK?

The Proxmox SDK provides a Pythonic, dynamic interface to the Proxmox REST API with:

  • Async-first design - Built on aiohttp for efficient concurrent operations
  • Multiple backends - HTTPS, SSH (Paramiko/OpenSSH), local pvesh, or mock
  • Type-safe - Full exception handling with meaningful error types
  • Session management - Automatic credential handling and ticket renewal
  • Real-world ready - Used in production for automation, monitoring, and infrastructure-as-code

Quick Overview

Installation

pip install proxmox-sdk

Basic Usage (3 ways)

1. Async Context Manager (Recommended)

import asyncio
from proxmox_sdk import ProxmoxSDK

async def main():
    async with ProxmoxSDK(
        host="pve.example.com",
        user="admin@pam",
        password="secret",
    ) as proxmox:
        nodes = await proxmox.nodes.get()
        print(nodes)

asyncio.run(main())

2. Synchronous (Blocking)

from proxmox_sdk import ProxmoxSDK

with ProxmoxSDK.sync(
    host="pve.example.com",
    user="admin@pam",
    password="secret",
) as proxmox:
    nodes = proxmox.nodes.get()
    print(nodes)

3. Manual Lifecycle (Async)

from proxmox_sdk import ProxmoxSDK

proxmox = ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="secret",
)
try:
    nodes = await proxmox.nodes.get()
finally:
    await proxmox.close()


Core Concepts

1. Navigation via Attributes

The SDK builds API paths using attribute access and function calls:

# Simple navigation
await proxmox.nodes.get()              # GET /api2/json/nodes

# With node name
await proxmox.nodes("pve1").get()      # GET /api2/json/nodes/pve1

# Deeper nesting
await proxmox.nodes("pve1").qemu.get()  # GET /api2/json/nodes/pve1/qemu

# Multiple segments
await proxmox.nodes("pve1").qemu(100).config.get()
# GET /api2/json/nodes/pve1/qemu/100/config

# Alternative: slash-separated ID
await proxmox.nodes("pve1/qemu/100").config.get()
# Same endpoint

# Alternative: list of segments
await proxmox.nodes(["pve1", "qemu", "100"]).config.get()
# Same endpoint

2. HTTP Methods

All HTTP methods return the response data (or task ID for long operations):

# GET — retrieve data
vms = await proxmox.nodes("pve1").qemu.get()

# POST — create or trigger action
task = await proxmox.nodes("pve1").qemu.post(
    vmid=100,
    name="my-vm",
    memory=2048
)

# PUT — replace/update
await proxmox.nodes("pve1").qemu(100).config.put(memory=4096)

# PATCH — partial update
await proxmox.nodes("pve1").qemu(100).config.patch(
    memory=4096
)

# DELETE — destroy
await proxmox.nodes("pve1").qemu(100).delete()

# Aliases
await proxmox.nodes("pve1").qemu.create(vmid=100, name="vm")  # = .post()
await proxmox.nodes("pve1").qemu(100).set(memory=8192)         # = .put()

3. Parameters & Data

Query parameters (GET, DELETE):

# GET with filter
await proxmox.nodes("pve1").qemu.get(status="running")
# GET /api2/json/nodes/pve1/qemu?status=running

Request body (POST, PUT, PATCH):

# POST with data
await proxmox.nodes("pve1").qemu.post(
    vmid=100,
    name="my-vm",
    memory=2048,
    cores=2
)

4. Error Handling

The SDK raises typed exceptions for different scenarios:

from proxmox_sdk import (
    ProxmoxSDK,
    ResourceException,
    AuthenticationError,
    BackendNotAvailableError,
)

try:
    await proxmox.nodes("pve1").qemu.post(vmid=100)
except ResourceException as e:
    print(f"API error: {e.status_code} - {e.status_message}")
    print(f"Error details: {e.errors}")
except AuthenticationError:
    print("Invalid credentials or token")
except BackendNotAvailableError:
    print("Required backend dependency not installed")

Available Backends

The SDK supports multiple backends for different environments:

Backend Use Case Installation
https (default) Connect to remote Proxmox server Built-in
ssh_paramiko SSH connection via Paramiko library pip install paramiko
openssh SSH via system openssh-wrapper pip install openssh_wrapper
local Direct CLI access (on Proxmox host) Built-in
mock Testing & development (no real server) Built-in

Configuration Options

HTTPS Backend

ProxmoxSDK(
    host="pve.example.com",           # Proxmox server address
    user="admin@pam",                  # Username with realm
    password="secret",                 # Password
    # OR
    token_name="api-token",            # API token ID (instead of password)
    token_value="xxxxxxxx-...",        # API token secret

    port=8006,                         # Custom port (default: 8006)
    verify_ssl=True,                   # Verify SSL cert (default: True)
    cert="/path/to/cert.pem",          # Custom CA cert
    timeout=5,                         # Request timeout in seconds
    otp="123456",                      # One-time password for 2FA
    otptype="totp",                    # OTP type: "totp" or "oath"
    backend="https",                   # Backend type
)

SSH Backend (Paramiko)

ProxmoxSDK(
    host="pve.example.com",
    user="root",
    password="secret",
    # OR
    private_key_file="/home/user/.ssh/id_rsa",

    backend="ssh_paramiko",
    # Paramiko-specific options
    identity_file="/custom/key",
    forward_ssh_agent=False,
    sudo=False,
)

Local Backend

ProxmoxSDK(
    backend="local",
    service="PVE",  # or "PMG", "PBS"
)
# Uses the local pvesh CLI — must be run on a Proxmox host!

Mock Backend

ProxmoxSDK(
    backend="mock",
)
# No credentials needed — returns simulated data

Authentication Methods

Method 1: Username & Password

Most common for user accounts:

ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="my-password",
)

More secure and fine-grained permissions:

ProxmoxSDK(
    host="pve.example.com",
    user="monitoring@pve",
    token_name="my-token",
    token_value="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
)

Method 3: Two-Factor Authentication (TOTP)

ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="password",
    otp="123456",  # Current TOTP code
    otptype="totp",
)

Method 4: SSH Key

ProxmoxSDK(
    host="pve.example.com",
    user="root",
    private_key_file="/home/user/.ssh/id_rsa",
    backend="ssh_paramiko",
)

Services & Versions

The SDK supports multiple Proxmox services:

# Proxmox VE (default)
ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="secret",
    service="PVE",
)

# Proxmox Mail Gateway
ProxmoxSDK(
    host="pmg.example.com",
    user="admin@pam",
    password="secret",
    service="PMG",
)

# Proxmox Backup Server
ProxmoxSDK(
    host="pbs.example.com",
    user="admin@pam",
    password="secret",
    service="PBS",
    port=8007,  # PBS uses port 8007 by default
)

PBS HOW-TO Guide

For a complete guide to PBS operations — datastores, snapshots, garbage collection, verification, pruning, and user management — see the Proxmox Backup Server HOW-TO →.


Patterns & Best Practices

async def deploy_vm():
    async with ProxmoxSDK(
        host="pve.example.com",
        user="admin@pam",
        password="secret",
    ) as proxmox:
        # Your code here
        nodes = await proxmox.nodes.get()
    # Automatically closes connection

Benefits: - Automatic resource cleanup - Exception-safe - Clean syntax

Pattern 2: Reuse Connection for Multiple Operations

async def setup_environment():
    async with ProxmoxSDK(...) as proxmox:
        # Multiple operations on same connection
        nodes = await proxmox.nodes.get()
        for node in nodes:
            status = await proxmox.nodes(node["node"]).status.get()
            print(f"Node {node['node']}: {status}")

Pattern 3: Handle Task IDs (Long Operations)

Many operations (create VM, backup, etc.) return a Task ID you can monitor:

from proxmox_sdk.sdk.tools import Tasks

async with ProxmoxSDK(...) as proxmox:
    # Create VM returns task ID
    result = await proxmox.nodes("pve1").qemu.post(
        vmid=100,
        name="my-vm"
    )

    task_id = result.get("upid")
    if task_id:
        # Monitor the task
        tasks_tool = Tasks(proxmox)
        status = await tasks_tool.wait_task(task_id)
        print(f"Task completed: {status}")

Pattern 4: File Operations

Upload and download backups or configs:

from proxmox_sdk.sdk.tools import Files

async with ProxmoxSDK(...) as proxmox:
    files_tool = Files(proxmox)

    # Download a file
    content = await files_tool.download(
        node="pve1",
        storage="local",
        filename="backup.tar"
    )

Next Steps


Troubleshooting

SSL Certificate Error

ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="secret",
    verify_ssl=False,  # Disable verification (development only!)
)

Or provide a custom CA:

ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="secret",
    cert="/path/to/cacert.pem",
)

Connection Timeout

ProxmoxSDK(
    host="pve.example.com",
    user="admin@pam",
    password="secret",
    timeout=30,  # Increase timeout
)

SSH Connection Issues

Ensure SSH is enabled and you have the right credentials:

# Test SSH connection manually first
ssh root@pve.example.com

# Ensure Paramiko is installed
pip install paramiko

Then:

ProxmoxSDK(
    host="pve.example.com",
    user="root",
    password="secret",
    backend="ssh_paramiko",
    forward_ssh_agent=True,  # Use SSH agent if available
)

See Also