Dashboard API Reference
Base URL: http://192.168.56.13:31880
Interactive API docs (Swagger UI): http://192.168.56.13:31880/docs
Authentication
Read operations are open. Mutating operations require a Bearer token:
Authorization: Bearer <DASHBOARD_ADMIN_TOKEN>
The token is set in dashboard/backend/.env (DASHBOARD_ADMIN_TOKEN).
Health
| Method |
Path |
Auth |
Description |
| GET |
/health |
— |
Backend liveness check |
Pods & Deployments (Control Room)
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/pods |
— |
List pods. Query: ?namespace=5g |
| GET |
/api/v1/pods/{pod}/describe |
— |
Describe a pod. Query: ?namespace=5g |
| POST |
/api/v1/deployments/{deployment}/restart |
✅ Admin |
Rolling restart a deployment. Query: ?namespace=5g |
ConfigMaps
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/configmaps/{name} |
— |
Read a ConfigMap. Query: ?namespace=5g |
| PUT |
/api/v1/configmaps/{name} |
✅ Admin |
Update a ConfigMap. Requires DASHBOARD_ALLOW_CONFIGMAP_WRITE=true |
Topology Map
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/topology |
— |
Pod nodes + OVS bridges with Multus interface metadata. Query: ?namespace=5g |
| GET |
/api/v1/network/nads |
— |
List NetworkAttachmentDefinitions. Query: ?namespace=5g |
| GET |
/api/v1/ovs/bridges/{bridge}/flows |
— |
OVS OpenFlow rules for a bridge (from ovs-ofctl dump-flows) |
Subscriber Management
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/subscribers |
— |
List all Open5GS subscriber records |
| POST |
/api/v1/subscribers |
✅ Admin |
Create a subscriber. Body: subscriber object |
| PUT |
/api/v1/subscribers/{imsi} |
✅ Admin |
Update a subscriber |
| DELETE |
/api/v1/subscribers/{imsi} |
✅ Admin |
Delete a subscriber |
| POST |
/api/v1/subscribers/init |
✅ Admin |
Trigger Ansible subscriber import (reset to defaults) |
UE Monitoring
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/ue/summary |
— |
Prometheus-backed gauges: gNBs, RAN UEs, PDU sessions, registration counts |
| GET |
/api/v1/ue/events |
— |
Log-parsed UE events. Query: ?minutes=10 |
| GET |
/api/v1/ue/active |
— |
Active UE list reconstructed from AMF/SMF logs |
| GET |
/api/v1/ue/pods |
— |
UERANSIM UE pod list |
| POST |
/api/v1/ue/test/ping |
✅ Admin |
Run ping from a UE pod. Body: {pod, namespace, target_ip} |
| POST |
/api/v1/ue/test/iperf |
✅ Admin |
Run iperf3 from a UE pod. Body: {pod, namespace, target_ip, duration} |
Metrics
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/metrics/nodes |
— |
Node-level CPU, memory, disk from Prometheus/Node Exporter |
| GET |
/api/v1/metrics/nf |
— |
Per-NF CPU, memory, restart counts |
RAN Mode Control
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/ran/status |
— |
Current RAN mode (physical / simulated / coexistence) and resource state |
| POST |
/api/v1/ran/enable |
✅ Admin |
Enable a RAN mode. Body: {mode: "physical" \| "simulated" \| "coexistence"} |
| POST |
/api/v1/ran/disable |
✅ Admin |
Disable a RAN mode. Body: {mode: "physical" \| "simulated"} |
See RAN Modes for the full workflow.
Physical RAN Config
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/physical-ran/interfaces |
— |
Available bridge interfaces on worker |
| GET |
/api/v1/physical-ran/status |
— |
OVS bridge state, AMF annotation state |
| POST |
/api/v1/physical-ran/setup |
✅ Admin |
Trigger Ansible OVS setup + AMF annotation patch |
Network Health
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/network/health |
— |
Cached N-interface connectivity results (N2/N3/N4/N6) |
| POST |
/api/v1/network/health/run |
— |
Trigger immediate health check (bypasses cache) |
Northbound (positioning / CAMARA)
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/northbound/services |
— |
Inventory of the camara/positioning/mec deployments (image, ready replicas, pods) |
| GET |
/api/v1/northbound/adapters |
— |
Live adapter registry from the engine (GET /adapters via the API-server service proxy): per adapter kind, registered_via, last_seen_s_ago, and derived state (live/unreachable/stale) |
| GET |
/api/v1/northbound/contract |
— |
Adapter contract guidance: Measurement schema, Python skeleton, env.contract.yaml template, doc links |
| GET |
/api/v1/northbound/contract/{service} |
— |
Live per-service contract fetched from the service's own /contract (kind, external_origin var, required/recommended/optional env). Degrades to {available: false} when the service exposes none |
| GET |
/api/v1/northbound/config/{service} |
— |
Guided-setup read: the contract plus current state (non-sensitive values; sensitive reported set/unset only, never the value) |
| PUT |
/api/v1/northbound/config/{service} |
✅ Admin |
Guided-setup apply. Body: {values: {VAR: value}}. Routes each var by the contract sensitive flag (Secret vs ConfigMap, both via envFrom), then rolls the deployment |
| DELETE |
/api/v1/northbound/adapters/{name} |
✅ Admin |
Force-remove a stale registry entry (engine DELETE /adapters/{name}). Adapters self-register, so there is no manual register endpoint |
| POST |
/api/v1/northbound/deploy |
✅ Admin |
Deploy a custom adapter image. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true. Body: {name, image, port, env[], image_pull_secret?, kind?}. The backend injects the self-registration env so the adapter announces itself to the engine |
| DELETE |
/api/v1/northbound/workloads/{name} |
✅ Admin |
Delete a deploy-from-image adapter (Deployment, Service, Secret) and unregister it |
| PUT |
/api/v1/northbound/fusion |
✅ Admin |
Update engine fusion config. Body: {strategy?, compare?, device_map?} |
| POST |
/api/v1/northbound/managed/{deployment}/image |
✅ Admin |
Retarget a managed deployment (gateway/engine/demo) to a new image. Body: {image} |
Edge apps (phase 12)
Operator-deployed application pods in the mec namespace; the local registry lives in the apps namespace. See architecture/edge-apps.md.
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/apps |
— |
Inventory of deployed apps (name, image, replicas, ready, exposed, public URL kelt-<name>.<base>, mec_attached, mec_ip) |
| GET |
/api/v1/apps/public |
— |
Unauthenticated (no token even in auth mode): names + public URLs of exposed apps, for the front-door welcome page |
| GET |
/api/v1/apps/updates |
— |
Per app: whether the registry digest for its tag is newer than the running pod's |
| POST |
/api/v1/apps |
✅ Admin |
Deploy an app. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true. Body: {name, image, port?, replicas?, env[], image_pull_secret?, expose?, attach_mec?, mec_ip?, udp_ports[]}. Creates a Deployment (+ Service on port 80 when exposed) pinned to the worker; attach_mec adds an n6m-net interface so UEs reach it over the user plane |
| PUT |
/api/v1/apps/{name}/image |
✅ Admin |
Retarget a deployed app to a chosen registry tag (date-ordered picker), preserving its other settings. Body: {image}. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true |
| DELETE |
/api/v1/apps/{name} |
✅ Admin |
Delete an app (Deployment, Service, config ConfigMap/Secret) |
| GET |
/api/v1/apps/registry-credentials |
✅ Admin |
Local-registry host + basic-auth credentials, so an admin can docker login and push |
| GET |
/api/v1/apps/registry/images |
✅ Admin |
Repos and tags in the local registry, each tag with its build timestamp (newest first) |
| GET |
/api/v1/apps/starter-kit |
✅ Admin |
Zip (README + .env.example + deploy.sh) prefilled with the registry host, for an app developer |
| POST |
/api/v1/apps/provision |
✅ Admin |
Deploy the platform from the UI (phases 12 + 11), streaming progress as NDJSON |
| GET |
/api/v1/apps/gnb/console |
— |
gNB management console state (configured, origin host:port, public URL) |
| PUT |
/api/v1/apps/gnb/console |
✅ Admin |
Expose the gNB web UI at kelt-gnb.<base>. Body: {host, port?}. Registers a selectorless Service+Endpoints gnb reached via the dynamic apps route. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true |
| DELETE |
/api/v1/apps/gnb/console |
✅ Admin |
Remove the gNB console Service+Endpoints |
Storage
Node disk usage and the reclaim actions. Sizes are measured by walking the filesystem, so they are cached; the filesystem totals are always live. See modules.md.
| Method |
Path |
Auth |
Description |
| GET |
/api/v1/storage |
— |
Worker disk breakdown: filesystem totals, containerd image layers vs blobs, persistent volumes (total and per claim, with namespace), the in-cluster registry as a subset of those, and journald. ?refresh=true re-walks instead of using the cache |
| GET |
/api/v1/storage/preview |
— |
Estimated saving per reclaim action: unused image count and bytes, and how far journald sits over its cap. Estimates, not promises: shared image layers are counted once per image, so the real saving is usually a little lower |
| POST |
/api/v1/storage/prune-images |
✅ Admin |
Remove image layers no container references. Returns bytes freed and free space after |
| POST |
/api/v1/storage/vacuum-journal |
✅ Admin |
Trim systemd journals to the 500M cap phase 01 configures |
| POST |
/api/v1/storage/registry-gc |
✅ Admin |
Garbage-collect unreferenced blobs in the in-cluster registry. ?dry_run=true (default) reports what would go, with the total size of those blobs, without touching the store |
WebSocket Endpoints
WebSocket connections are made to the same host on port 31880.
Log streaming
WS /api/v1/ws/logs/{namespace}/{pod}?container=<name>
Streams live container logs. Equivalent to kubectl logs -f. The server closes the connection when the pod disappears or the client disconnects.
Messages (server → client): JSON {line: "...", timestamp: "..."} per log line.
Traffic intensity
WS /api/v1/ws/traffic/intensity
Streams real-time OVS bridge counter deltas every second.
Messages (server → client):
{
"bridges": {
"br-n2": {"rx_packets": 42, "tx_packets": 38, "rx_bytes": 5400, "tx_bytes": 4800},
"br-n3": {"rx_packets": 120, ...},
...
},
"timestamp": "2026-03-11T10:00:01Z"
}
Planned / Stubbed
| Method |
Path |
Description |
| POST |
/api/v1/experiments/run |
Run a test scenario |
| POST |
/api/v1/snapshot/create |
Create a testbed state snapshot |