proxmoxer turns the Proxmox API into nested Python attributes
python wrapper for Proxmox API v2 (https://pve.proxmox.com/pve-docs/api-viewer/index.html)
At a glance
- What is it?
- proxmoxer is a Python wrapper around the Proxmox REST API v2 that creates attributes on demand, so paths from the API viewer become attribute chains in your script. It covers PVE, PMG and PBS, and reaches the same API over HTTPS, SSH or the pvesh shell.
- Who is it for?
- Infrastructure engineers automating Proxmox from Python should adopt proxmoxer, because the dynamic attribute model removes the need to hand-build request paths and the ssh and pvesh backends let the same script work where the API is not reachable over HTTPS.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 29 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Attributes that appear because you asked for them
proxmoxer is a Python wrapper around the Proxmox REST API v2, and the design decision that defines it is that attributes are created dynamically.
The README describes it plainly: like Proxmoxia, it dynamically creates attributes which respond to the attributes you have attempted to reach. You do not declare a tree of endpoints. You write proxmox.nodes.get() and the object builds itself around the call, returning whatever the API returned.
That is a Pythonic choice with a real trade-off, which this article returns to later. In exchange you get a very short mapping between the API documentation and your code, because the paths from the PVE API v2 are the same paths you type.
The scope is the Proxmox family rather than a single product. The library currently supports the Proxmox services of Proxmox Virtual Environment, Proxmox Mail Gateway and Proxmox Backup Server. So the same wrapper and the same call style reach a cluster manager, a mail gateway and a backup server, which is convenient when one script has to talk to all three.
The project was inspired by slumber, with the stated difference that proxmoxer is dedicated only to Proxmox. It is MIT licensed, published on PyPI, and developed by Oleg Butovich.
Three transports, one API surface
The unusual capability in this library is that the API is reachable three ways.
The README states that it allows not only REST API use over HTTPS, but the same API over ssh and the pvesh utility. That is a bigger deal than it sounds. Proxmox installations are often locked down so that the API is reachable only from certain hosts, or so that TLS is terminated by something in front of the cluster, or so that a firewall rule simply does not allow the API port. A wrapper that can fall back to SSH or to the pvesh command on the node keeps the script identical in those cases.
Each transport has its own optional dependency, and the README lists them one by one. The https backend needs requests, the ssh_paramiko backend needs paramiko, and the openssh backend needs openssh_wrapper. The default is https, and the README notes that you must have the required libraries installed for the connection method you are using. That last point matters in containers and in CI images, where a missing paramiko is a runtime error rather than an install-time one.
Because pvesh is a command line utility that runs on the node, the ssh and pvesh routes are effectively a way of executing Proxmox commands on a machine you already have a shell on, rather than talking to an HTTP endpoint. The trade is a different performance profile and a different authentication story, but the same Python call structure.
Queries as nested attribute chains
Once you have a connection object, the API surface is reached through the four HTTP verbs the library exposes: get, post, put and delete. Two synonyms are provided for convenience, create for post and set for put, which reads better in the places where those verbs make sense.
The example in the README shows how the attribute chain maps onto the API paths:
>>> for node in proxmox.nodes.get():
... for vm in proxmox.nodes(node["node"]).qemu.get():
... print(f"{vm['vmid']}. {vm['name']} => {vm['status']}")
...proxmox.nodes.get() lists the nodes, the node name is pulled out of the returned dictionary, and that name is passed back into proxmox.nodes() to scope the next call to qemu.get() for the guests on that node. The output in the README is a list of virtual machines with their id, name and status.
Two conventions are worth copying into your own scripts. First, the resource name is a method, so proxmox.nodes(node["node"]) is a call and not an attribute lookup, and the same call returns a new scoped object. Second, the arguments travel in the query string, which is why the API path structure is what you are reading in the code.
The path in the code is literally the path from the PVE API v2 documentation, which is what makes the wrapper easy to learn: you look the endpoint up in the API viewer and you type it.
Installing it and making the first connection
Installation is a pip install, and the transport you use decides what else you need:
pip install proxmoxer
pip install requestsThose two cover the default https backend. The ssh_paramiko backend needs paramiko, and the openssh backend needs openssh_wrapper:
pip install paramiko
pip install openssh_wrapperThe connection object is created with a host, a user and a password:
from proxmoxer import ProxmoxAPI
proxmox = ProxmoxAPI(
"proxmox_host", user="admin@pam", password="secret_word", verify_ssl=False
)The user in the example, admin@pam, is the format Proxmox uses for local users, and by default this connects to PVE through the https backend.
One line in that snippet deserves a warning. verify_ssl=False disables certificate verification for the whole connection, and the README uses it in its own example. That is convenient against a lab cluster with a self-signed certificate and it is the wrong default for anything else, because it removes the protection that lets you trust the server you are sending an administrative password to. Set it to True, or point the client at your certificate authority, before this code runs against a real cluster.
Full documentation is hosted at proxmoxer.github.io/docs, and the changelog is kept in CHANGELOG.md in the repository.
Version 2 broke things, so the migration notes matter
proxmoxer is on version 2, and the README treats the move from version 1 as something you should read about before you upgrade.
There is a dedicated Migration Docs page for the minimal steps needed to update to version 2, and the library keeps a changelog file that the README points to directly. That combination tells you the project has had at least one breaking change to its public surface, which is unsurprising for a library whose surface is generated dynamically at runtime.
The release history shows the pace. Version 2.1.0 added files tools and bugfixes and shipped on 2024-08-10, version 2.2.0 shipped bugfixes on 2024-12-15, and version 2.3.0 added 2FA, a proxy and improved error handling on 2026-03-04.
Those three features are the ones worth noting. Two factor authentication support matters because a cluster with TOTP or WebAuthn enabled cannot be scripted with a password alone. Proxy support matters for the same reason the ssh backend does: network topology gets in the way, and a proxy is one more way around it. Improved error handling matters for anyone running this in a pipeline, because the difference between an exception you can read and one you cannot is the difference between a retry and a page.
The default branch is develop, with master also in the repository and CI badges for both, so the released version on PyPI and the branch you clone are not the same thing.
Where the dynamic model costs you
The attribute model is the whole idea and the whole cost, so it is worth being concrete about the downside.
Nothing about the API surface exists at import time. If you mistype a path segment, or if a Proxmox version does not expose an endpoint you expected, you find out when the call runs, and the failure is an attribute error or a 404 rather than a clear message at the point of the mistake. You also lose editor completion and static type checking on the paths themselves, which is a real cost on a large codebase that calls a dozen different endpoints.
The wrapper is also only as good as its version coverage. The library targets Proxmox 2.x APIs, and the supported Python versions listed in the package classifiers run from 3.10 through 3.14. If your cluster runs an API endpoint that the wrapper does not expose, the fallback is to drop down to the raw request layer rather than to the library.
And the scope is narrow by design. This is a Proxmox client, so if your estate includes something other than PVE, PMG and PBS, it does nothing for it. The README also does not document anything about concurrency or sessions beyond what the connection object exposes, so high fan-out scripts should be tested before they are trusted in anger.
One more practical note: the example passes a password as a plain string. For anything beyond a lab, the credential handling is yours to design.
MIT licensed, actively packaged, Python 3.10 to 3.14
The licence is MIT, declared in the package metadata and shipped as LICENSE.txt at the root of the repository. That is permissive enough to use the wrapper inside commercial automation without a separate grant, with the usual notice requirement when you redistribute it.
The packaging is ordinary and well maintained. The repository holds a pyproject.toml, a setup.cfg, a setup.py and MANIFEST.in, and the version is read from the package itself, with the setup script importing the version from proxmoxer. The pyproject configuration is minimal and only configures black with a line length of 100 and a target version of py37. There are separate dependency files for development and for tests, and the CI setup is a GitHub Actions workflow with a coverage service badge, plus a .pre-commit-config.yaml, a .bandit file for static security checks and a devcontainer configuration.
The release record shows the project is still being packaged. The last push was on 2026-09-26, and the repository is not archived. The newest release, 2.3.0, dates from 2026-03-04, so there have been commits since the last tag, which is normal for a library whose development happens on the develop branch.
The distribution channel is PyPI, and the README points to the package page through its badge. The documentation site carries the full reference, with the migration guide for version 2 living there alongside the API pages.
Editorial conclusion
Infrastructure engineers automating Proxmox from Python should adopt proxmoxer, because the dynamic attribute model removes the need to hand-build request paths and the ssh and pvesh backends let the same script work where the API is not reachable over HTTPS. It is the wrong choice for a script that needs static analysis or editor completion, since every attribute is created at runtime, and it is the wrong choice for anything beyond Proxmox, because the library is dedicated to that platform. Before adopting, set verify_ssl to True outside a lab, read the version 2 migration notes, and check that your Python version is one the package classifiers list.
Frequently asked questions
How do I install proxmoxer and connect to a Proxmox host?
Run pip install proxmoxer and pip install requests, then create a ProxmoxAPI instance with the host, user and password. The default connection uses the https backend, and the README notes that the libraries for the connection method you choose must be installed.
Which Proxmox products does proxmoxer support?
It currently supports the Proxmox services of Proxmox Virtual Environment, Proxmox Mail Gateway and Proxmox Backup Server. It also allows the same API to be reached over ssh or through the pvesh utility, not only over HTTPS.
How do I call an API endpoint in proxmoxer?
Queries are exposed through get, post, put and delete, with create as a synonym for post and set as a synonym for put. The attribute path matches the path in the PVE API v2 documentation, so listing guests on a node is proxmox.nodes(node["node"]).qemu.get().
What changed in proxmoxer version 2?
The README points to dedicated migration documentation for the minimal steps needed to update to version 2, and the changelog is kept in CHANGELOG.md. The latest release, 2.3.0, added 2FA, proxy support and improved error handling.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/proxmoxer-proxmoxer)Was this useful?