Hand-written selection · last reviewed 2026-09-19 against v0.45.0
This document covers the key endpoints for integration and technical qualification: about 74 of the 218 routes the API exposes, organized by functional domain, with a curl example for each. It is a selection, not an inventory, and it is written by hand — so it lags.
The authoritative list is docs/openapi.json, regenerated by the pre-commit hook on every
route change and guarded in CI. Anything absent here may still exist; check there first.
Routes added recently and deliberately not covered below include the LLM backend rates, agent
identities and inference-log ingestion.
Interactive reference (Swagger UI): https://<host>/docs
Machine-readable spec: docs/openapi.json (OpenAPI 3.1 — 213 paths, 269 operations, auto-generated)
Full redoc: https://<host>/redoc
All protected endpoints require Authorization: Bearer <token> in the request header.
The token is a JWT enriched with org_id, teams, role, and scope.
Authenticates a user and returns an access token + refresh token.
curl -s -X POST https://<host>/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "secret"}' | jq .Response:
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer"
}Exchanges a refresh token (7-day validity) for a new access token.
curl -s -X POST https://<host>/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "eyJ..."}'Returns the UserContext associated with the current token (org_id, role, teams, scope).
curl -s https://<host>/api/v1/auth/me \
-H "Authorization: Bearer $TOKEN" | jq .Allows the authenticated user to change their own password.
curl -s -X PATCH https://<host>/api/v1/me/password \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"current_password": "old", "new_password": "new"}'Liveness probe — no I/O, always 200 if the process is up. Used by Kubernetes.
curl -s https://<host>/api/v1/health/liveDeep health — checks DB and Redis. Returns 200 if all dependencies are up, 503 otherwise.
curl -s https://<host>/api/v1/health | jq .Response:
{
"status": "ok",
"db": "ok",
"redis": "ok"
}Jobs are the core execution primitive. Every infrastructure action (scale, deploy, delete…) creates a job. All jobs are org-scoped, audited, and policy-checked.
Job lifecycle: pending → running → success | failed | cancelled
Creates a job. Passes through 4 guards: auth, rate limiter, PolicyEngine, GPU quota.
Destructive actions (scale_cluster, delete_deployment, helm_install, helm_upgrade, helm_uninstall…) return 409 with a
dry-run preview unless confirmed: true is present. The confirmed flag can only be injected
by the confirm_action agent tool — it is stripped from direct API calls.
# Non-destructive: list cluster deployments
curl -s -X POST https://<host>/api/v1/jobs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "get_cluster_deployments",
"payload": {"cluster_name": "prod-cluster"},
"gateway_id": "gw-abc123"
}' | jq .# Destructive: dry-run preview (confirmed omitted → 409)
curl -s -X POST https://<host>/api/v1/jobs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "scale_cluster",
"payload": {"cluster_name": "prod-cluster", "node_group": "gpu-pool", "desired_count": 0},
"gateway_id": "gw-abc123"
}'
# → 409: {requires_confirmation: true, preview: "...", reversibility: "reversible", resolved_params: {...}}Response 201:
{
"id": "3fa8e1b2-...",
"action": "get_cluster_deployments",
"status": "pending",
"org_id": "org-xyz",
"triggered_by": "user:admin",
"created_at": "2026-05-01T10:00:00Z"
}Lists jobs for the current org. Filterable by status, action, triggered_by, gateway_id.
curl -s "https://<host>/api/v1/jobs?status=failed&limit=20" \
-H "Authorization: Bearer $TOKEN" | jq .Returns a job by full UUID or short ID (first 8 chars). Includes result once completed.
curl -s https://<host>/api/v1/jobs/3fa8e1b2 \
-H "Authorization: Bearer $TOKEN" | jq .Response (completed):
{
"id": "3fa8e1b2-...",
"status": "success",
"result": {
"returncode": 0,
"stdout": "...",
"execution_time_ms": 342
}
}SSE stream of job logs in real time. Terminates when the job reaches a terminal state.
curl -s -N https://<host>/api/v1/jobs/3fa8e1b2/logs/stream \
-H "Authorization: Bearer $TOKEN"Cancels a pending or running job. The worker finishes its current iteration then stops.
curl -s -X POST https://<host>/api/v1/jobs/3fa8e1b2/cancel \
-H "Authorization: Bearer $TOKEN"Pipelines are ordered sequences of jobs. Steps execute sequentially — if one fails, the pipeline
stops. Each step is policy-checked at creation time; at execution time only unknown_action is
re-checked (system jobs are pre-authorized).
Creates and queues a pipeline.
curl -s -X POST https://<host>/api/v1/pipelines \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "deploy-llama3-prod",
"steps": [
{"action": "helm_upgrade", "payload": {"release": "llama3", "namespace": "staging", "confirmed": true}, "gateway_id": "gw-abc123"},
{"action": "get_cluster_deployments", "payload": {"cluster_name": "prod-cluster"}, "gateway_id": "gw-abc123"},
{"action": "helm_upgrade", "payload": {"release": "llama3", "namespace": "prod", "confirmed": true}, "gateway_id": "gw-abc123"}
],
"on_failure": "rollback"
}' | jq .on_failure values: stop (default) | rollback | continue
Lists pipelines for the current org (paginated).
curl -s "https://<host>/api/v1/pipelines?limit=10" \
-H "Authorization: Bearer $TOKEN" | jq .Returns a pipeline with its step results.
Triggers an existing pipeline immediately. Returns 202 Accepted.
curl -s -X POST https://<host>/api/v1/pipelines/uuid-here/trigger \
-H "Authorization: Bearer $TOKEN"Gateways (VibOps Connect) are edge agents deployed in the customer's infrastructure. They bridge Core to local Kubernetes clusters, cloud APIs, and AI connectors.
Lists registered gateways and their last ping timestamp.
curl -s https://<host>/api/v1/gateways \
-H "Authorization: Bearer $TOKEN" | jq .Response:
[
{
"id": "gw-abc123",
"name": "prod-vpc",
"status": "online",
"last_ping": "2026-05-01T09:58:00Z",
"version": "0.13.0"
}
]Registers a new gateway. Returns the bearer token (shown once — store it immediately).
gateway_type values: kubernetes (default) | slurm | hybrid
slurm_config is required when gateway_type is slurm or hybrid.
curl -s -X POST https://<host>/api/v1/gateways \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-hpc",
"description": "Production HPC gateway",
"gateway_type": "slurm",
"slurm_config": {
"host": "gpu.hpc.acme.com",
"ssh_user": "slurm",
"ssh_port": 22,
"rest_url": "http://gpu.hpc.acme.com:6820",
"ssh_key_secret": "slurm_ssh_key"
}
}' | jq .Response:
{
"id": "gw-abc123",
"name": "prod-hpc",
"gateway_type": "slurm",
"slurm_config": {
"host": "gpu.hpc.acme.com",
"ssh_user": "slurm",
"ssh_port": 22,
"rest_url": "http://gpu.hpc.acme.com:6820",
"ssh_key_secret": "***"
},
"token": "gw-tk-xxxxxxxxxxxxxxxx"
}Revokes a gateway token. The gateway will no longer be able to poll for jobs.
The workloads API provides access to the persistent GPU workload tracking table (workloads), populated every 60 seconds by KubernetesWorkloadCollector (DCGM/ROCm-SMI via Prometheus) and SlurmWorkloadCollector (squeue + sacct). Available since v0.17.3.
Returns GPU metrics (utilisation, memory, power, accumulated GPU-seconds) for a specific workload.
Query params: none required.
curl -s "https://<host>/api/v1/clusters/prod-hpc/workloads/ml-team/job-4829/gpu-metrics" \
-H "Authorization: Bearer $TOKEN" | jq .Response:
{
"workload_id": "job-4829",
"workload_type": "slurm_job",
"namespace": "ml-team",
"status": "running",
"gpu_util_pct": 87.4,
"gpu_memory_mb": 40960,
"power_w": 312.5,
"gpu_seconds": 14400,
"started_at": "2026-05-12T08:00:00Z",
"ended_at": null
}workload_type: k8s_pod | slurm_job
Returns aggregated GPU metrics for all workloads in a namespace (or Slurm partition).
Query params:
status— filter by workload status:running|completed|terminated(optional)limit— max results (default: 50)
curl -s "https://<host>/api/v1/clusters/prod-gpu/namespaces/ml-team/gpu-metrics?status=running" \
-H "Authorization: Bearer $TOKEN" | jq .Response:
{
"namespace": "ml-team",
"workload_count": 12,
"total_gpu_util_pct": 73.2,
"total_gpu_memory_mb": 491520,
"total_power_w": 3750,
"workloads": [...]
}Returns the top N workloads by GPU utilisation across all namespaces in a cluster.
Query params:
limit— number of results (default: 10, max: 100)workload_type— filter byk8s_podorslurm_job(optional)
curl -s "https://<host>/api/v1/clusters/prod-gpu/gpu-metrics/top?limit=10" \
-H "Authorization: Bearer $TOKEN" | jq .Response:
[
{
"workload_id": "llm-inference-7b-6d4f9",
"workload_type": "k8s_pod",
"namespace": "prod",
"gpu_util_pct": 94.1,
"gpu_memory_mb": 32768,
"gpu_seconds": 86400
}
]Fetches real-time GPU instance prices from cloud provider APIs and syncs them into cluster cost rates.
Preview the hourly price for any (provider, instance type, region, pricing tier) without saving anything.
Query parameters
| Parameter | Required | Description |
|---|---|---|
provider |
✓ | aws · azure · gcp |
instance_type |
✓ | e.g. p5.48xlarge, Standard_ND96isr_H100_v5, a3-highgpu-8g |
region |
✓ | e.g. us-east-1, eastus, us-central1 |
pricing_tier |
— | on_demand (default) · spot · reserved_1y · reserved_3y |
curl -s "https://<host>/api/v1/cloud-pricing/lookup?provider=aws&instance_type=p5.48xlarge®ion=us-east-1&pricing_tier=on_demand" \
-H "Authorization: Bearer $TOKEN" | jq .Response:
{
"provider": "aws",
"instance_type": "p5.48xlarge",
"region": "us-east-1",
"pricing_tier": "on_demand",
"instance_hourly_rate_usd": 98.32,
"accelerators_per_instance": 8,
"rate_per_gpu_hour_usd": 12.29,
"source": "api",
"currency": "USD"
}source: "api" (live from provider) or "static" (GCP cached table).
Fetches the live price and saves it as the cluster GPU rate in one call.
curl -s -X POST "https://<host>/api/v1/clusters/h100-prod/rate/sync" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "aws",
"instance_type": "p5.48xlarge",
"region": "us-east-1",
"pricing_tier": "on_demand",
"markup_pct": 20
}' | jq .Body fields:
| Field | Required | Description |
|---|---|---|
provider |
✓ | aws · azure · gcp |
instance_type |
✓ | Instance type (must be in the supported catalogue) |
region |
✓ | Cloud region |
pricing_tier |
— | Defaults to on_demand |
markup_pct |
— | Chargeback markup % (0 = pass-through). Keeps existing value if omitted. |
Response:
{
"cluster_name": "h100-prod",
"provider": "aws",
"instance_type": "p5.48xlarge",
"region": "us-east-1",
"pricing_tier": "on_demand",
"instance_hourly_rate_usd": 98.32,
"accelerators_per_instance": 8,
"rate_per_gpu_hour_usd": 12.29,
"markup_pct": 20.0,
"source": "api",
"synced_at": "2026-06-14T03:00:00Z"
}After sync, GET /clusters/{name}/rate returns the updated rate_per_gpu_hour.
Daily auto-refresh — Celery Beat re-syncs all clusters that have formula_type="cloud" at 03:00 UTC automatically. No manual action required once configured.
Supported instance types (selection)
| Provider | Instance | GPUs | GPU model |
|---|---|---|---|
| AWS | p5.48xlarge |
8 | H100 80GB |
| AWS | p4d.24xlarge |
8 | A100 40GB |
| AWS | p4de.24xlarge |
8 | A100 80GB |
| AWS | g5.48xlarge |
8 | A10G |
| Azure | Standard_ND96isr_H100_v5 |
8 | H100 80GB |
| Azure | Standard_ND96asr_v4 |
8 | A100 40GB |
| Azure | Standard_NC96ads_A100_v4 |
4 | A100 80GB |
| GCP | a3-highgpu-8g |
8 | H100 80GB |
| GCP | a2-highgpu-8g |
8 | A100 40GB |
| GCP | a2-ultragpu-8g |
8 | A100 80GB |
Full list: GET /cloud-pricing/lookup returns 422 with all known types on unknown input.
Webhook endpoints receive external events and translate them into VibOps jobs.
Receives a GitHub push or release event. If a subscription matches repo + branch, creates a job.
Authenticated via HMAC-SHA256 (X-Hub-Signature-256 header).
# GitHub sends this automatically — configure in repo Settings → Webhooks
# URL: https://<host>/api/v1/webhooks/github
# Content-Type: application/json
# Secret: value of GITHUB_WEBHOOK_SECRET env varReceives a Grafana Alertmanager alert payload. For each firing alert with a known action, creates
a VibOps job. Authenticated via Authorization: Bearer <GRAFANA_WEBHOOK_SECRET>.
# Configure in Grafana: Alerting → Contact points → Webhook
# URL: https://<host>/api/v1/webhooks/grafana
# Authorization header: Bearer <secret>Lists the current org's GitHub webhook subscriptions.
Registers a repo → action subscription.
curl -s -X POST https://<host>/api/v1/webhooks/subscriptions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"repo": "acme/ml-models",
"branch": "main",
"event": "push",
"action": "helm_upgrade",
"payload": {"release": "llama3", "namespace": "prod", "confirmed": true},
"gateway_id": "gw-abc123"
}'Deletes a subscription.
Triggers are persistent rules that fire jobs on a schedule (cron) or on metric threshold events.
Creates a trigger rule.
# Cron-based: scale down GPUs every night at 22:00
curl -s -X POST https://<host>/api/v1/triggers \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "nightly-scale-down",
"type": "cron",
"schedule": "0 22 * * *",
"action": "scale_cluster",
"payload": {"cluster_name": "prod-cluster", "node_group": "gpu-pool", "desired_count": 0},
"gateway_id": "gw-abc123"
}'Lists triggers. Use ?enabled_only=true to filter.
Enables or disables a rule without deleting it.
Permanently deletes a trigger rule.
The agent's persistent memory store. Used across conversations to retain cluster-specific facts, preferences, and operational context. Scoped to the organization.
Creates or updates a memory (upsert by org_id + key).
curl -s -X POST https://<host>/api/v1/memories \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key": "prod_cluster_owner",
"value": "infra-team",
"type": "fact",
"description": "Primary responsible team for the prod cluster"
}'type values: app | preference | fact | action
Lists the org's memories. Filter by type: ?type=fact
Full-text search over memory keys and descriptions.
curl -s "https://<host>/api/v1/memories/search?q=gpu+quota" \
-H "Authorization: Bearer $TOKEN" | jq .Retrieves a memory by exact key.
Permanently deletes a memory.
Secrets are encrypted at rest with Fernet (SECRET_KEY). Values are never returned on list
operations — only via explicit GET /api/v1/secrets/{name}.
Encrypts and stores a secret.
curl -s -X POST https://<host>/api/v1/secrets \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "prod_kubeconfig", "value": "base64-encoded-kubeconfig"}'Lists secret names (no values exposed).
Returns a secret with its decrypted value. Checks org vault first, then global vault.
Deletes a secret from the org vault.
Discovery scans the connected infrastructure and builds a resource inventory.
Launches a background scan. Returns immediately with a job_id.
curl -s -X POST https://<host>/api/v1/discovery/run \
-H "Authorization: Bearer $TOKEN" | jq .
# → {"job_id": "3fa8e1b2-..."}
# Poll GET /api/v1/jobs/3fa8e1b2 to track progressReturns the result of the last successfully completed discovery — cluster topology, deployments, GPU counts, Prometheus presence.
Servers managed over the DMTF Redfish API through their BMC — iDRAC, iLO, XCC. See ADR 0040.
The inventory is declared: a network scan proposes what it finds, an operator
confirms what VibOps may talk to. A node stays managed: false until someone says
otherwise, and a rescan never changes that flag. Reaching a management network means
being able to power off a building, so the confirmation is deliberate rather than
implied.
Credentials are never carried by this API. A node holds the name of a vault secret; the value is resolved immediately before execution.
# The whole inventory
curl -s https://<host>/api/v1/bare-metal/nodes -H "Authorization: Bearer $TOKEN"
# Only what a scan proposed and nobody has confirmed
curl -s "https://<host>/api/v1/bare-metal/nodes?managed=false" -H "Authorization: Bearer $TOKEN"
# → {"items": [{"node_id": "rack4-node01", "address": "10.20.0.11",
# "manufacturer": "Dell Inc.", "model": "PowerEdge R760xa",
# "managed": true, "source": "discovery", "insecure": false, ...}],
# "total": 1}Declare a server by hand — for one a scan cannot reach. Requires org_admin.
curl -s -X POST https://<host>/api/v1/bare-metal/nodes \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"node_id": "rack4-node01", "address": "10.20.0.11",
"username": "vibops", "password_secret": "bmc_fleet_password"}'
# → 201 with the created node
# → 409 if node_id already exists in this organisationConfirm a node, or stop managing it. Requires org_admin.
# Confirm — VibOps may now talk to this BMC
curl -s -X PATCH https://<host>/api/v1/bare-metal/nodes/$ID \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"managed": true}'
# An explicit null clears a field; an omitted field is left alone
curl -s -X PATCH https://<host>/api/v1/bare-metal/nodes/$ID \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ca_bundle": null}'Removes it from the inventory. A later scan may propose it again. Requires org_admin.
Record what a scan found. Proposes only — every node lands unmanaged, and an
existing node's managed flag is the one field this endpoint will not touch.
curl -s -X POST https://<host>/api/v1/bare-metal/nodes/discovered \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"nodes": [{"node_id": "10.20.0.21", "address": "10.20.0.21",
"manufacturer": "Dell Inc."}]}'
# → {"created": 1, "refreshed": 0, "awaiting_confirmation": 1}A gateway does not normally call this: its heartbeat already carries
discovered_services, and core extracts the Redfish entries from it.
The four read actions are connector tools, reached through POST /api/v1/jobs
like any other action — redfish_list_nodes, redfish_get_node,
redfish_get_firmware, redfish_get_bios. Core injects the confirmed inventory
into the payload, so the caller names a machine by its node_id and never by its
address.
curl -s -X POST https://<host>/api/v1/jobs \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"action": "redfish_get_firmware", "payload": {"id": "rack4-node01"}}'The audit log records every job (success and denied), the matched policy rule, and the outcome.
Lists the audit log for the current org (paginated, filterable).
curl -s "https://<host>/api/v1/audit?limit=50&action=scale_cluster" \
-H "Authorization: Bearer $TOKEN" | jq .Fields per entry: job_id, action, outcome (allowed|denied), matched_rule, reason,
triggered_by, org_id, created_at.
Exports audit events in bulk for ingestion into a SIEM (Splunk, QRadar, ArcSight, Elastic).
Query parameters
| Parameter | Default | Description |
|---|---|---|
format |
json |
json · cef (ArcSight/Splunk) · leef (IBM QRadar) |
limit |
10000 |
Max events to export (ceiling: 50 000) |
since |
— | ISO 8601 datetime — export events after this timestamp |
until |
— | ISO 8601 datetime — export events before this timestamp |
action |
— | Filter by action name |
JSON export (default)
curl -s "https://<host>/api/v1/audit/export?format=json&limit=5000" \
-H "Authorization: Bearer $TOKEN" > audit_export.jsonResponse includes a signed manifest:
{
"exported_at": "2026-06-14T09:00:00Z",
"count": 4832,
"format": "json",
"events": [...],
"manifest": {
"count": 4832,
"exported_at": "2026-06-14T09:00:00Z",
"sha256": "a3f1..."
},
"manifest_signature": "hmac-sha256:9c2e..."
}Verify integrity with the manifest_signature (HMAC-SHA256 keyed with SECRET_KEY).
CEF export (ArcSight / Splunk)
curl -s "https://<host>/api/v1/audit/export?format=cef&since=2026-06-01T00:00:00Z" \
-H "Authorization: Bearer $TOKEN" > audit.cefEach line follows the ArcSight CEF standard:
CEF:0|VibOps|VibOps|1.0|deploy_model|deploy_model|5|rt=1718352000000 suser=alice@acme.com ...
LEEF export (IBM QRadar)
curl -s "https://<host>/api/v1/audit/export?format=leef" \
-H "Authorization: Bearer $TOKEN" > audit.leefEach line follows the LEEF 2.0 format:
LEEF:2.0|VibOps|VibOps|1.0|deploy_model| usrName=alice sev=5 devTime=...
Automation example — nightly cron to Splunk HEC:
#!/bin/bash
SINCE=$(date -u -d "yesterday" +%Y-%m-%dT00:00:00Z)
UNTIL=$(date -u -d "today" +%Y-%m-%dT00:00:00Z)
curl -s "https://$VIBOPS_HOST/api/v1/audit/export?format=cef&since=$SINCE&until=$UNTIL" \
-H "Authorization: Bearer $VIBOPS_TOKEN" | \
curl -s -X POST "https://$SPLUNK_HEC_URL/services/collector/raw" \
-H "Authorization: Splunk $SPLUNK_HEC_TOKEN" \
--data-binary @-All DELETE endpoints in VibOps follow a two-step confirmation pattern to prevent accidental data loss.
Step 1 — dry-run preview (default, no ?confirmed=true)
curl -s -X DELETE "https://<host>/api/v1/tokens/abc123" \
-H "Authorization: Bearer $TOKEN"{
"action": "delete_token",
"token": {"id": "abc123", "name": "ci-deploy"},
"confirmed": false,
"warning": "This API token will be permanently revoked. Add ?confirmed=true to execute."
}Step 2 — execute (add ?confirmed=true)
curl -s -X DELETE "https://<host>/api/v1/tokens/abc123?confirmed=true" \
-H "Authorization: Bearer $TOKEN"{"deleted": true, "id": "abc123"}This pattern applies to: DELETE /tokens/{id}, DELETE /webhooks/subscriptions/{id},
DELETE /notifications/channels/{id}, DELETE /orgs/{id}/teams/{id},
DELETE /orgs/{id}/invites/{id}, DELETE /orgs/{id}/teams/{id}/members/{user_id},
DELETE /alert-rules/{id}, DELETE /providers/{id}, DELETE /eval/rubrics/{id},
DELETE /memories/{key}, DELETE /policy.
Returns the current licence status: plan, expiry, usage vs limits.
curl -s https://<host>/api/v1/licence \
-H "Authorization: Bearer $TOKEN" | jq .Response:
{
"plan": "enterprise",
"valid": true,
"expires_at": "2027-04-22",
"days_remaining": 365,
"limits": {
"users_max": 50,
"clusters_max": 10,
"gpu_max": 128
},
"usage": {
"users_current": 12,
"clusters_current": 3,
"gpu_current": 32
}
}Applies a new licence key (RS256 JWT signed by VibOps vendor key).
curl -s -X POST https://<host>/api/v1/licence \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"licence_key": "eyJ..."}'Returns live GPU metrics (utilisation, memory, temperature, error counts) aggregated across all connected gateways.
curl -s https://<host>/api/v1/metrics/gpu \
-H "Authorization: Bearer $TOKEN" | jq .Returns workload metrics (request rate, latency, replica counts per deployment).
Returns cost metrics (estimated hourly/daily GPU spend per cluster).
Returns mean time to recovery metrics from the incident history.
Returns all registered actions across all connectors, merged with any per-org policy overrides.
Access: any authenticated user (viewer+).
curl -s https://<host>/api/v1/catalog \
-H "Authorization: Bearer <token>" | jq .Response:
{
"total": 162,
"tools": [
{
"action": "accelerator_get_metrics",
"connector": "Nvidia",
"description": "Collect live GPU utilization, memory, temperature and power from DCGM.",
"required_role": "viewer",
"destructive": false,
"requires_confirmation": false,
"requires_external_approval": false,
"overridden": false,
"input_schema": {
"type": "object",
"properties": {
"node": { "type": "string", "description": "Filter by node name (optional)" }
}
}
}
]
}overridden: true means your org has an active policy override on this action.
Create or update the per-org policy override for a specific action.
Access: org_admin only. Passing null for a flag removes that override (reverts to connector default).
# Force confirmation before helm_upgrade for this org
curl -s -X PATCH https://<host>/api/v1/catalog/helm_upgrade \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"requires_confirmation": true}' | jq .
# Remove the confirmation override (revert to connector default)
curl -s -X PATCH https://<host>/api/v1/catalog/helm_upgrade \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"requires_confirmation": null}' | jq .Body fields (all optional):
| Field | Type | Description |
|---|---|---|
requires_confirmation |
boolean | null |
Override confirmation flag; null removes the override |
requires_external_approval |
boolean | null |
Override approval flag; null removes the override |
Returns the full ToolEntry object with updated values and "overridden": true.
These endpoints require admin role or org_admin scope.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/admin/org |
Create an organisation |
GET |
/api/v1/admin/org |
Get the current org details |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/admin/teams |
List teams |
POST |
/api/v1/admin/teams |
Create a team (with optional scope: namespaces, clusters, actions) |
PATCH |
/api/v1/admin/teams/{team_id}/scope |
Update a team's scope |
DELETE |
/api/v1/admin/teams/{team_id} |
Delete a team |
POST |
/api/v1/admin/teams/{team_id}/members |
Add a member |
DELETE |
/api/v1/admin/teams/{team_id}/members/{user_id} |
Remove a member |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/admin/users |
List org users |
POST |
/api/v1/admin/users |
Create a user (enforces users_max licence limit) |
PATCH |
/api/v1/admin/users/{user_id} |
Update user role or status |
Per-cluster role overrides — grant a different role to a user on a specific cluster, independent of their team membership. Requires org_admin.
Resolution order: explicit cluster assignment → team-level role.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/orgs/{org_id}/cluster-roles |
List all cluster role assignments in the org |
GET |
/api/v1/orgs/{org_id}/users/{user_id}/cluster-roles |
List assignments for a specific user |
PUT |
/api/v1/orgs/{org_id}/users/{user_id}/cluster-roles/{cluster_name} |
Create or update assignment (idempotent) |
DELETE |
/api/v1/orgs/{org_id}/users/{user_id}/cluster-roles/{cluster_name} |
Remove assignment (user reverts to team role) |
Body for PUT: {"role": "readonly" | "developer" | "admin"}
Example — readonly on prod, developer on dev:
# Lock alice to readonly on prod
PUT /api/v1/orgs/{org_id}/users/{alice_id}/cluster-roles/prod
{"role": "readonly"}
# Give alice developer access on dev
PUT /api/v1/orgs/{org_id}/users/{alice_id}/cluster-roles/dev
{"role": "developer"}Service accounts for the agent and external integrations.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/admin/tokens |
List API tokens |
POST |
/api/v1/admin/tokens |
Create a token (returns the token value once) |
DELETE |
/api/v1/admin/tokens/{token_id} |
Revoke a token |
| Code | Meaning |
|---|---|
400 |
Validation error — check request body |
401 |
Missing or invalid JWT |
403 |
Action not in TOOL_CATALOG, or insufficient role |
404 |
Resource not found (or not owned by this org) |
409 |
Destructive action requires confirmation — response includes preview and resolved_params |
429 |
Rate limit exceeded (60 requests / 60 seconds / org) |
503 |
Core dependency down (DB or Redis) — see GET /api/v1/health |
60 requests per 60-second sliding window per organisation. Tracked in Redis (ZSET + Lua script). The limit applies per org, not per user — a single user cannot exhaust another org's quota.
| Document | Purpose |
|---|---|
docs/openapi.json |
Full OpenAPI 3.1 spec (machine-readable, 132 endpoints) |
https://<host>/docs |
Swagger UI — interactive, testable |
docs/technical-architecture.md |
Customer-facing architecture document (DAT) |
docs/architecture/security.md |
Auth layers, PolicyEngine, threat model |
docs/architecture/overview.md |
System diagram, action flows, trust boundaries |