Skip to main content

Calling the API

How a token authenticates a call, which endpoints it reaches, and the quotas that pace it.

Authenticating a call​

Send the full secret as a bearer token. That is the only accepted form: there is no API key header, no query parameter, no cookie.

curl -fsS \
-H 'Authorization: Bearer pxc_REPLACE_WITH_YOUR_TOKEN' \
https://proxcenter.example.com/api/v1/public/health

No CORS header is emitted on these responses. The API is meant for server-to-server callers, not for a page running in a browser.

Layered catalog of the checks an API token call goes through, in order, each with its refusal. In the proxy, before any lookup: the route must be on the token allowlist, else the ordinary 401, and the method must be declared on the route, else 405 Method not allowed for this API token route with an Allow header. Token lookup: a known, unexpired token, else 401 Invalid or expired API token; an enabled tenant, else 403 API token tenant is disabled or missing; the API Access add-on, else 403 Feature not licensed. Then the read or write quota window, else 429 Rate limit exceeded with Retry-After, and only after it the scope held for the route, else 403 Route not available to API tokens, so a call refused for its scope has already used its quota. Before the handler: connections inside the perimeter, else 403 Connection not in token scope; for a vDC tenant token, no cluster-level object, else 403 Cluster-level object not available to a vDC tenant token, and a guest inside its vDC, else 403 Guest outside your vDC scope; for a write, the creator still holds the right, else 403 Token creator no longer holds this right. The handler then runs its usual RBAC checks. The audit log records apitoken.write for every token write and apitoken.denied for refusals after the proxy.Layered catalog of the checks an API token call goes through, in order, each with its refusal. In the proxy, before any lookup: the route must be on the token allowlist, else the ordinary 401, and the method must be declared on the route, else 405 Method not allowed for this API token route with an Allow header. Token lookup: a known, unexpired token, else 401 Invalid or expired API token; an enabled tenant, else 403 API token tenant is disabled or missing; the API Access add-on, else 403 Feature not licensed. Then the read or write quota window, else 429 Rate limit exceeded with Retry-After, and only after it the scope held for the route, else 403 Route not available to API tokens, so a call refused for its scope has already used its quota. Before the handler: connections inside the perimeter, else 403 Connection not in token scope; for a vDC tenant token, no cluster-level object, else 403 Cluster-level object not available to a vDC tenant token, and a guest inside its vDC, else 403 Guest outside your vDC scope; for a write, the creator still holds the right, else 403 Token creator no longer holds this right. The handler then runs its usual RBAC checks. The audit log records apitoken.write for every token write and apitoken.denied for refusals after the proxy.
The order in which a token call is checked. The first check that fails gives the answer, and a call refused for a missing scope has already used its quota.

A refused call answers with one of the following:

StatusBodyCause
401Invalid or expired API tokenUnknown, deleted, revoked or expired token. Every case is answered identically on purpose, and a WWW-Authenticate: Bearer realm="proxcenter" header is returned
403Route not available to API tokensThe token does not hold a scope the endpoint requires
403Connection not in token scopeThe connection named in the path is outside the token's perimeter
403API token tenant is disabled or missingThe token's tenant was disabled or deleted
403Feature not licensedThe API Access add-on is not active
403Cluster-level object not available to a vDC tenant tokenA vDC tenant token reached a cluster or node level object
403Guest outside your vDC scopeA vDC tenant token named a guest that is not in its vDC
403Token creator no longer holds this rightA write was refused because the creator lost the right, see Who can mint a write token
405Method not allowed for this API token routeThe method does not exist on this path. The Allow header lists the ones that do
503Unable to verify token scopeThe perimeter or scope lookup failed. The call is denied rather than let through, retry
429Rate limit exceededThe token's quota for the current minute is used up

Endpoints​

Seven monitoring endpoints are exposed, all GET. They are reachable with the read scopes listed in Scopes. The GET endpoints of the opened write routes (for example the guest config, the snapshot list or the HA groups) are also reachable with a read token, see Write endpoints:

EndpointScopeReturns
/api/v1/public/healthany valid tokenApplication status plus per-connection reachability, filtered by tenant
/api/v1/public/metricsnodes:read, vms:read or backups:readPrometheus text exposition of fleet metrics
/api/v1/public/backupsbackups:readFleet-wide backup freshness per guest: latest backup date, age in seconds, datastore, PBS server, size and verification state. Guests with no backup at all are listed with a null age
/api/v1/vmsvms:readAggregated VM and container list with status, usage and config-derived fields
/api/v1/inventorynodes:readMulti-cluster inventory tree: clusters, nodes, guests and PBS servers
/api/v1/storagestorage:readEvery storage of the visible PVE connections, with capacity and usage
/api/v1/pbs/{id}/backupsbackups:readSnapshots of one PBS server, every datastore and namespace, paginated

Query parameters:

EndpointParameters
/api/v1/vmsconnId to restrict to one connection, include=agent to probe the QEMU guest agent on running VMs (about 7 times slower)
/api/v1/inventoryrefresh=true to force a blocking refresh instead of reading the shared cache
/api/v1/pbs/{id}/backupsdatastore, namespace (empty string for the root), type (vm, ct or host), page, pageSize, search

In /api/v1/pbs/{id}/backups, {id} is a ProxCenter connection id. It is checked against the token's perimeter before the handler runs, so a connection the token may not read never reaches Proxmox.

tip

The health, metrics and inventory endpoints answer from ProxCenter's own caches, so scraping them on a short interval does not multiply calls to your Proxmox clusters. The VM, storage and backup listings do query Proxmox and PBS, as do refresh=true on the inventory and include=agent on the VM list. Scrape those less often.

An OpenAPI 3.1 description of every endpoint, read and write, with request bodies and the required scope on each operation, ships with the image and is served at /openapi/proxcenter-public-api.json.

The API reference page​

The same document is rendered inside the product, under Settings > API reference (/settings/api-reference). Open it with the API reference button of the Settings > API tab, or from the command palette (Ctrl/Cmd + K) with Open the API reference. Each endpoint is listed with its parameters and responses, and a Try it panel sends the request to the instance you are logged in to, authenticated with a token as described above, so a call can be checked against your own fleet before it goes into a scraper or a script.

Command palette with api ref typed and the action Open the API reference highlighted
Type api ref in the command palette (Ctrl/Cmd + K) to open the API reference from anywhere.

The page is gated exactly like the token tab: a super_admin acting in the provider tenant. It does not depend on the API Access add-on, so the reference is readable before the option is licensed. It follows the dark or light mode of your session and shows the white-label logo and name when branding defines them. Nothing leaves your browser but the requests you send from Try it: the embedded viewer has no request proxy, no telemetry, no remote fonts, no AI assistant, and it does not remember the token you paste.

API reference page with the hint that requests go to this ProxCenter instance, Back to API tokens, the warning that write operations act on your real infrastructure, and the ProxCenter public API overview with the server https://proxcenter.example.com and the Bearer token authentication
The API reference sends its requests to the instance you are signed in to, and warns that write operations act on your real infrastructure.
Try it panel of the API reference on GET /api/v1/public/metrics, with a masked example pxc_ token in the Bearer field and a 200 OK response listing proxcenter_vm_status series for the guests web-01, app-01 and monitor-01
Paste a token in Try it and send the request to check what an endpoint returns for your own fleet before scripting against it.

Quotas​

Each token gets its own quota, 600 requests per minute by default, counted in a fixed window aligned on the clock minute. Writes are counted in a separate write bucket, 60 writes per minute by default, so a busy automation cannot starve your monitoring reads and a read scrape cannot eat the write budget. The write limit is set per token in the creation dialog (Writes per minute), which is shown only when a domain is on Write.

Every answer to a token carries the current state of the window it was counted in, the read window for a GET, the write window for any other method:

HeaderMeaning
RateLimit-LimitRequests allowed per minute for this token
RateLimit-RemainingRequests left in the current window
RateLimit-ResetSeconds until the window resets

Beyond the quota the call is refused with HTTP 429 Rate limit exceeded and a Retry-After header, in seconds. The window is consumed before the scope check, so a call refused for a missing scope still counts against it.

info

Both quotas are set when the token is created and cannot be changed afterwards: there is no edit route. A different ceiling means creating another token.

Counters are held in the frontend process, so on a control-plane HA stack the effective ceiling is multiplied by the number of active nodes.

Each call also records a Last used timestamp and the caller's IP address, refreshed at most once a minute.