HTTP API Reference¶
This page summarizes the HTTP endpoints exposed by proxbox-api.
For full request and response schemas, use the runtime OpenAPI at /docs.
Root and Utilities¶
GET /- Service metadata and links.GET /version- Backend service version for external cache invalidation.GET /cache- Inspect the in-memory cache snapshot.GET /clear-cache- Clear the in-memory cache.GET /cache/metrics- JSON snapshot of NetBox GET cache metrics (hit ratio, entries, byte usage).GET /cache/metrics/prometheus- Prometheus text-format exposition of the same metrics for scrape jobs.
Authentication (/auth)¶
All requests except bootstrap endpoints require the X-Proxbox-API-Key header. See Authentication for the full bootstrap flow and key management guide.
GET /auth/bootstrap-status- Check whether first-time key registration is still needed. Auth-exempt.POST /auth/register-key- Register the first API key. Auth-exempt; fails once a key already exists.POST /auth/keys- Create a new API key. Returns the raw key value once; store it securely.GET /auth/keys- List all API keys. Key values are redacted (only metadata is returned).DELETE /auth/keys/{key_id}- Delete an API key by ID.POST /auth/keys/{key_id}/activate- Re-activate a previously deactivated key.POST /auth/keys/{key_id}/deactivate- Deactivate an active key without deleting it.
Admin¶
GET /admin/- HTML admin dashboard for the configured NetBox endpoint records. This route is excluded from OpenAPI.GET /admin/logs- In-memory backend log buffer with optional filters forlevel,limit,offset,since, andoperation_id.GET /admin/logs/stream- SSE real-time log stream. Supports query parameterslevel,errors_only,operation_id, andnewer_than_id.
NetBox Routes (/netbox)¶
POST /netbox/endpoint- Create the singleton NetBox endpoint.GET /netbox/endpoint- List NetBox endpoint records.GET /netbox/endpoint/{netbox_id}- Get endpoint by ID.PUT /netbox/endpoint/{netbox_id}- Update endpoint.DELETE /netbox/endpoint/{netbox_id}- Delete endpoint.GET /netbox/status- Fetch NetBox API status.GET /netbox/openapi- Fetch NetBox OpenAPI.
NetBox singleton rule¶
Attempting to create a second endpoint returns HTTP 400 with:
Proxmox Routes (/proxmox)¶
Endpoint configuration CRUD¶
POST /proxmox/endpointsGET /proxmox/endpointsGET /proxmox/endpoints/{endpoint_id}PUT /proxmox/endpoints/{endpoint_id}DELETE /proxmox/endpoints/{endpoint_id}
Validation rules:
- Provide
password, or bothtoken_nameandtoken_value. token_nameandtoken_valuemust be set together.- Endpoint names must be unique.
Session and discovery¶
GET /proxmox/sessionsGET /proxmox/versionGET /proxmox/GET /proxmox/storageGET /proxmox/nodes/{node}/storage/{storage}/contentGET /proxmox/{top_level}wheretop_levelis one ofaccess,cluster,nodes,storage, orversionGET /proxmox/{node}/{type}/{vmid}/config
Cluster, node, and replication data¶
GET /proxmox/cluster/statusGET /proxmox/cluster/resourcesGET /proxmox/nodes/GET /proxmox/nodes/{node}/networkGET /proxmox/nodes/{node}/qemuGET /proxmox/replication
High-Availability (read-only)¶
Aggregated across every configured Proxmox cluster. These endpoints back the
HA tab on the NetBox VM detail page and the cluster-wide HA page added by
netbox-proxbox for issue #243.
Mutations (add/remove resource, migrate/relocate, group CRUD) are intentionally
out of scope and may be added in a follow-up release.
GET /proxmox/cluster/ha/status- Per-service CRM/LRM rows from/cluster/ha/status/current, plus quorum/master entries.GET /proxmox/cluster/ha/resources- Configured HA resources merged with their live runtime state (node, CRM state, request state).GET /proxmox/cluster/ha/resources/by-vm/{vmid}- Convenience lookup for a single VM/CT id; triesvm:{vmid}then falls back toct:{vmid}. Returnsnull(not 404) when the guest is not HA-managed so the NetBox tab can render an empty state.GET /proxmox/cluster/ha/groups- List of HA groups with merged detail (nodes, restricted, nofailback).GET /proxmox/cluster/ha/groups/{group}- Single group detail across clusters; returnsnullwhen no cluster has the group.GET /proxmox/cluster/ha/summary- Single envelope ({status, groups, resources}) composed in parallel viaasyncio.gather. Used by the NetBox cluster-wide HA page so a render only triggers one round-trip.
VM Operational Verbs¶
POST verbs that act on a single QEMU VM or LXC container. Implemented in proxbox_api/routes/proxmox_actions.py. Each handler is gated by ProxmoxEndpoint.allow_writes; the gate runs before any NetBox or Proxmox call, so a write-disabled endpoint returns 403 even when the downstream services are unreachable.
All verb routes accept:
endpoint_id(query parameter, required) — selects the target Proxmox cluster among many.Idempotency-Key(header, optional) — 60-second cache window per(endpoint_id, verb, vmid). A second POST with the same key returns the cached body without re-dispatching.X-Proxbox-Actor(header, optional) — actor label written to the NetBox journal entry. Defaults toproxbox-api.
Every invocation (success, failure, or no-op) writes exactly one journal entry on the linked NetBox VirtualMachine resolved by the proxmox_vm_id custom field.
| Method | Path | Purpose |
|---|---|---|
POST |
/proxmox/qemu/{vmid}/start |
Start a QEMU VM. State-based no-op when already running (result: "already_running"). |
POST |
/proxmox/lxc/{vmid}/start |
Start an LXC container. Same no-op rule. |
POST |
/proxmox/qemu/{vmid}/stop |
Stop a QEMU VM. State-based no-op when already stopped (result: "already_stopped"). |
POST |
/proxmox/lxc/{vmid}/stop |
Stop an LXC container. Same no-op rule. |
POST |
/proxmox/qemu/{vmid}/snapshot |
Create a QEMU snapshot. Optional JSON body {snapname, description}; when snapname is omitted the route generates proxbox-{idempotency_key[:8]} or proxbox-{utc_stamp}. Always dispatched (no state-based no-op). |
POST |
/proxmox/lxc/{vmid}/snapshot |
Create an LXC snapshot. Same body and default rules. |
POST |
/proxmox/qemu/{vmid}/migrate |
Migrate a QEMU VM. Required body {target, online}. Runs a preflight against /nodes/{node}/qemu/{vmid}/migrate and rejects when the target is not allowed or online=true would hit local disks/resources. Returns 202 Accepted with proxmox_task_upid and sse_url (the cancel/stream endpoints below). |
POST |
/proxmox/lxc/{vmid}/migrate |
Migrate an LXC container. Same body and 202 shape. |
DELETE |
/proxmox/qemu/{vmid}/migrate/{task_upid} |
Best-effort cancel of an in-flight migrate task. Journals the cancel intent even if Proxmox refuses. |
DELETE |
/proxmox/lxc/{vmid}/migrate/{task_upid} |
Best-effort cancel for LXC migrate. |
GET |
/proxmox/qemu/{vmid}/migrate/{task_upid}/stream |
SSE stream emitting migrate_dispatched, repeated migrate_progress, then migrate_succeeded xor migrate_failed. |
GET |
/proxmox/lxc/{vmid}/migrate/{task_upid}/stream |
SSE stream for LXC migrate task progress. |
allow_writes gate (403 shape)¶
When endpoint_id is missing, the endpoint does not exist, or ProxmoxEndpoint.allow_writes is false, the handler returns HTTP 403 with one of three reason codes:
{
"reason": "endpoint_writes_disabled",
"detail": "Operational verbs are disabled on this endpoint. Enable ProxmoxEndpoint.allow_writes on the NetBox side after granting core.run_proxmox_action to the operator group.",
"endpoint_id": 7
}
Other 403 shapes use reason: "endpoint_id_required" or reason: "endpoint_not_found" and omit endpoint_id. The gate is the load-bearing trust boundary documented in docs/design/operational-verbs.md §2.3 layer 3 — it must remain the first check in every handler.
Response shape (success / no-op)¶
{
"verb": "start",
"vmid": 100,
"vm_type": "qemu",
"endpoint_id": 7,
"result": "ok",
"dispatched_at": "2026-05-13T14:22:08Z",
"proxmox_task_upid": "UPID:pve1:00012E34:...",
"journal_entry_url": "/api/extras/journal-entries/42/"
}
result is one of ok, already_running, already_stopped, accepted (migrate dispatch), cancel_requested, cancel_failed, rejected, or failed. Error paths add reason and detail. The migrate 202 response also carries sse_url, target, online, and source_node.
Viewer and generated contract helpers¶
POST /proxmox/viewer/generate- Crawl the Proxmox API Viewer and generate OpenAPI + Pydantic artifacts. Acceptsversion_tag,workers,persist, and other tuning query parameters.GET /proxmox/viewer/openapi- Return the generated Proxmox OpenAPI document.GET /proxmox/viewer/openapi/embedded- Return an embedded subset of the generated OpenAPI.GET /proxmox/viewer/integration/contracts- Report Proxmox and NetBox schema contract sources.POST /proxmox/viewer/routes/refresh- Rebuild runtime-generated Proxmox routes from disk without restarting. Accepts optionalversion_tagto rebuild a single version.GET /proxmox/viewer/schema-status- Report available bundled schema versions and active background generation tasks. Accepts optionalversion_tagto inspect a specific version.GET /proxmox/viewer/pydantic- Return generated Pydantic v2 model source code.
See Schema Management for the full workflow guide and the proxbox-schema CLI reference.
Runtime-generated live proxy routes¶
proxbox-api mounts runtime-generated Proxmox proxy routes from the embedded generated OpenAPI contract under:
/proxmox/api2/{version_tag}/*/proxmox/api2/*as a compatibility alias tolatest
Behavior:
- Routes are built at startup for every generated version present under
proxbox_api/generated/proxmox/. - The mounted route set is cached in
proxbox_api/generated/proxmox/runtime_generated_routes_cache.json. - On
uvicorn --reload, startup prefers that cache manifest so the previously mounted live route set is preserved in development. - Routes are rebuilt on demand with
POST /proxmox/viewer/routes/refresh. POST /proxmox/viewer/routes/refreshwith no query parameters rebuilds all available generated versions.POST /proxmox/viewer/routes/refresh?version_tag=8.3rebuilds only that mounted version.- The unversioned
/proxmox/api2/*alias forwards to thelatestgenerated contract. - Request bodies and responses are validated with runtime-generated Pydantic models.
- Generated response models cover object, array, scalar, and
nullresponse schemas. - For array responses whose items are objects, generation emits
{Operation}ResponseItemplusRootModel[list[{Operation}ResponseItem]]so Swagger shows concrete item fields. - Generated routes appear in FastAPI
/docsand/openapi.json. latestroutes are mounted before older version tags so they appear first in Swagger.- Generated routes are prioritized ahead of older handcrafted
/proxmox/*routes so path collisions resolve to the generated API surface.
Path parameter normalization:
- When the Proxmox viewer uses path parameter names that are not valid FastAPI identifiers, the mounted FastAPI route uses a normalized placeholder name.
- Example:
- Proxmox contract path:
/nodes/{node}/hardware/pci/{pci-id-or-mapping} - Mounted FastAPI path:
/proxmox/api2/latest/nodes/{node}/hardware/pci/{pci_id_or_mapping} - The upstream proxmox-sdk SDK call still uses the original Proxmox parameter name from the generated OpenAPI contract.
Version discovery:
- A version is mountable only when
proxbox_api/generated/proxmox/<version-tag>/openapi.jsonexists. - Non-version entries such as
__pycache__and files at the root ofgenerated/proxmox/are ignored.
Target selection:
- If exactly one Proxmox endpoint exists, generated routes use it automatically.
- If more than one endpoint exists, pass one of:
target_nametarget_domaintarget_ip_addresssourceselects whether endpoints come from the local database or NetBox plugin records.
Typed sync integration:
- Handcrafted sync-facing routes still call Proxmox directly, but now do so through
proxbox_api/services/proxmox_helpers.pybacked by the proxmox-sdk SDK. - That helper layer validates live proxmox-sdk payloads with the generated models in
proxbox_api/generated/proxmox/latest/pydantic_models.pybefore returning data to route handlers. - This avoids internal HTTP round-trips while keeping VM config, cluster status, cluster resources, storage listing, and node storage content aligned with the generated contract used by
/proxmox/api2/*.
Examples of generated route shapes:
GET /proxmox/api2/latest/cluster/resourcesGET /proxmox/api2/8.3/nodes/{node}/qemu/{vmid}/configPOST /proxmox/api2/latest/access/aclGET /proxmox/api2/cluster/resourcesas the compatibility alias forlatest
Refresh response shape:
- Top-level response: registration summary from
register_generated_proxmox_routes()plus the message field. state: nested snapshot fromgenerated_proxmox_route_state().state.mounted_versions: the versioned route sets currently mounted in FastAPI.state.alias_version_tag: the version used by/proxmox/api2/*.state.cache_path: persisted manifest path used to preserve generated routes across reloads.state.cache_enabled: whether cache persistence is enabled for generated routes.state.loaded_from_cache: whether the latest registration used the persisted runtime cache.state.route_count: total generated FastAPI routes currently mounted.state.versions.<tag>.route_count: number of FastAPI routes mounted for that version.state.versions.<tag>.path_count: number of OpenAPI paths mounted for that version.state.versions.<tag>.method_count: number of HTTP operations mounted for that version.state.versions.<tag>.schema_version: theinfo.versionvalue from the generated OpenAPI document.
Test coverage:
tests/test_generated_proxmox_routes.pyruns a mock-based exhaustive route suite over every generated operation for every available version plus thelatestalias.tests/test_pydantic_generator_models.pyverifies generated response models for array, scalar,null, and aliased object payloads.tests/test_session_and_helpers.pyverifies the typed proxmox helper layer and confirms the handcrafted sync dependencies return helper-validated payloads.
DCIM Routes (/dcim)¶
GET /dcim/devicesGET /dcim/devices/create- Create NetBox devices from Proxmox nodes.GET /dcim/devices/create/stream- SSE streaming variant.GET /dcim/devices/{node}/interfaces/createGET /dcim/devices/interfaces/create- Sync all node interfaces across all clusters.GET /dcim/devices/interfaces/create/stream- SSE streaming variant for all-node interface sync.
Virtualization Routes (/virtualization)¶
GET /virtualization/cluster-types/create- Stub that returns HTTP 501.GET /virtualization/clusters/create- Stub that returns HTTP 501.GET /virtualization/virtual-machines/create- Create NetBox VMs from Proxmox resources.GET /virtualization/virtual-machines/create/stream- SSE streaming variant.GET /virtualization/virtual-machines/{netbox_vm_id}/create- Create a single VM by NetBox ID.GET /virtualization/virtual-machines/{netbox_vm_id}/create/stream- SSE streaming variant for single VM sync.GET /virtualization/virtual-machines/GET /virtualization/virtual-machines/{id}GET /virtualization/virtual-machines/{id}/summary- Stub that returns HTTP 501.GET /virtualization/virtual-machines/summary/exampleGET /virtualization/virtual-machines/interfaces/createGET /virtualization/virtual-machines/interfaces/create/streamGET /virtualization/virtual-machines/interfaces/ip-address/createGET /virtualization/virtual-machines/interfaces/ip-address/create/streamGET /virtualization/virtual-machines/backups/createGET /virtualization/virtual-machines/backups/all/createGET /virtualization/virtual-machines/backups/all/create/streamGET /virtualization/virtual-machines/{netbox_vm_id}/backups/create/streamGET /virtualization/virtual-machines/snapshots/createGET /virtualization/virtual-machines/snapshots/all/createGET /virtualization/virtual-machines/snapshots/all/create/streamGET /virtualization/virtual-machines/{netbox_vm_id}/snapshots/create/streamGET /virtualization/virtual-machines/virtual-disks/createGET /virtualization/virtual-machines/virtual-disks/create/streamGET /virtualization/virtual-machines/{netbox_vm_id}/virtual-disks/create/streamGET /virtualization/virtual-machines/storage/createGET /virtualization/virtual-machines/storage/create/stream
VM stream overwrite query parameters¶
Every VM stream endpoint listed above (/virtualization/virtual-machines/...create/stream) accepts the SyncOverwriteFlags query parameters defined in proxbox_api/schemas/sync.py. They control which user-managed NetBox fields the sync may overwrite:
overwrite_vm_tags,overwrite_vm_role,overwrite_vm_platform,overwrite_vm_description,overwrite_vm_custom_fieldsoverwrite_cluster_tags,overwrite_storage_tags,overwrite_node_interface_tags,overwrite_ip_tagssync_vm_network- whenfalse, skips the VM-network sub-step.
See Overwrite Flags for the full matrix and defaults.
Full Update¶
GET /full-update- Runs device sync, storage sync, VM sync, task history sync, disk sync, backup sync, snapshot sync, node interface sync, VM interface sync, VM IP sync, replication sync, and backup routine sync.GET /full-update/stream- SSE streaming variant.
Sync State Probe¶
GET /sync/active- Returns{ active, started_at, id, kind, runs }reporting whether this API replica currently has a/full-updateor/full-update/streamrequest in flight. Use this to fast-fail a cron / single-exec invocation when a sync is already running.
The registry is process-local and memory-only, so the probe answers for the worker that handles the request. With multiple uvicorn workers, callers may see disagreeing answers across workers; treat the response as advisory and keep the scheduling interval larger than the typical sync duration. The endpoint is covered by the standard X-Proxbox-API-Key middleware.
Response shape:
{
"active": true,
"started_at": "2026-05-12T17:53:28.122Z",
"id": "9b6c0408-...",
"kind": "full-update",
"runs": [
{ "id": "9b6c0408-...", "kind": "full-update", "started_at": "2026-05-12T17:53:28.122Z" }
]
}
started_at / id / kind report the oldest in-flight run (FIFO). runs lists every registered run on the local replica for diagnostics.
WebSocket¶
GET /- Basic counter WebSocket for connectivity checks.GET /ws/virtual-machines- WebSocket-triggered VM synchronization.GET /ws- Command-driven WebSocket for sync orchestration.
SSE Streaming Format¶
All /stream endpoints return Content-Type: text/event-stream and emit three event types:
| Event | Description |
|---|---|
step |
Progress frame with step, status, message, rowid, and payload. |
error |
Error frame with step, status: "failed", error, and detail. |
complete |
Final frame with ok, message, and optionally result or errors. |
Headers:
Cache-Control: no-cacheX-Accel-Buffering: no
Sync Individual Routes (/sync/individual)¶
GET /sync/individual/nodeGET /sync/individual/vmGET /sync/individual/vm/{cluster_name}/{node}/{type}/{vmid}GET /sync/individual/clusterGET /sync/individual/interfaceGET /sync/individual/ipGET /sync/individual/diskGET /sync/individual/storageGET /sync/individual/snapshotGET /sync/individual/task-historyGET /sync/individual/backupGET /sync/individual/replicationGET /sync/individual/backup-routines
Extras Routes (/extras)¶
GET /extras/extras/custom-fields/create
This endpoint creates the custom fields used by VM synchronization metadata.
Proxbox Plugin Config Routes¶
These route handlers exist in proxbox_api/routes/proxbox/__init__.py but are not currently mounted in main.py:
GET /netbox/plugins-configGET /netbox/default-settingsGET /settings
Mounting them requires including that router in app startup if desired.