REST API reference
The manager exposes a single REST API rooted at /api. The SPA in web/ calls it; you can call it directly with any HTTP client. There is no GraphQL, no gRPC for application traffic (gRPC is only used for the geminio tunnel, internal to the manager).
This page is a route catalogue, not a hand-written swagger spec. Source of truth: cmd/ongrid/main.go (the chi.Router mounts) and internal/manager/server/*/http.go (the per-BC handlers). Click through to the handler for exact request/response struct fields.
Conventions
- Base path: every route is prefixed
/api. SoGET /v1/edgesis reached athttps://<manager>/api/v1/edges. - Versioning: all routes are under
/v1/. There is no/v2/. Backwards-incompatible changes ship behind feature flags or new routes. - Auth: bearer JWT in
Authorization: Bearer .... Public routes (login, refresh, register, IM webhooks, Prometheus's auth_request probe) skip the middleware. Listed in the "Public" table below. - Roles:
admin,user,viewer. Write routes requireadmin(or the relevant casbin action likeedge:* / write); read routes accept any authed role.viewercan chat but the agent's toolbag is filtered toClassSafe. See ADR-022 three-role RBAC. - Errors: JSON
{"error":"code","message":"human text"}. Codes are stable enums (not_found,invalid_argument,unauthorized,forbidden,conflict). - Content type: every request and response is
application/jsonunless explicitly noted (streamed chat is SSE, log/trace ingest is OTLP-protobuf or Loki-JSON).
Public routes (no auth)
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz | liveness probe |
| GET | /readyz | readiness probe |
| GET | /internal/auth/dataplane-verify | nginx auth_request probe for log/trace ingest |
| POST | /api/v1/auth/login | exchange email+password for JWT |
| POST | /api/v1/auth/refresh | exchange refresh token for a fresh access token |
| POST | /api/v1/auth/register | self-registration (gated by config) |
| GET | /api/v1/prometheus/auth | nginx auth_request probe for the Grafana embed |
| POST | /api/v1/im/feishu/events | inbound Feishu/Lark callback; webhook signature is the auth |
Authenticated routes
iam (users, orgs, sessions)
| Method | Path | Role | Source |
|---|---|---|---|
| GET | /v1/version | any | cmd/ongrid/main.go (inline) |
| GET | /v1/me | any | internal/iam/server/http.go |
| GET | /v1/self | any | internal/iam/server/http.go |
| GET | /v1/users | any | list users |
| POST | /v1/users | admin | create user |
| PATCH | /v1/users/{id} | admin | update user (name, email) |
| PATCH | /v1/users/{id}/password | self or admin | rotate password |
| PATCH | /v1/users/{id}/role | admin | change role (admin/user/viewer) |
| DELETE | /v1/users/{id} | admin | remove user |
| GET | /v1/orgs | any | list orgs |
| POST | /v1/orgs | admin | create org |
| PATCH | /v1/orgs/{id} | admin | update org |
| DELETE | /v1/orgs/{id} | admin | remove org |
| GET | /v1/orgs/{id}/members | any | list members |
| POST | /v1/orgs/{id}/members | admin | add member |
| PATCH | /v1/orgs/{id}/members/{user_id} | admin | change member role |
| DELETE | /v1/orgs/{id}/members/{user_id} | admin | remove member |
edge (the tunnel-connected agent)
| Method | Path | Role | Description |
|---|---|---|---|
| POST | /v1/edges | edge:* | create edge, issues access+secret keys |
| GET | /v1/edges | any | list edges |
| GET | /v1/edges/{id} | any | get edge detail |
| DELETE | /v1/edges/{id} | edge:* | delete edge |
| POST | /v1/edges/{id}/rotate-secret | edge:* | rotate the secret key |
| POST | /v1/edges/{id}/upgrade | edge:* | trigger remote agent upgrade with explicit URL+sha256 |
| POST | /v1/edges/{id}/upgrade-package | edge:* | one-click bundle upgrade (ADR-024) |
| GET | /v1/edges/{id}/processes | any | read-only process list (on-demand RPC) |
| GET | /v1/edges/{id}/plugins | any | list edge's configured + live plugins (with health) |
| PUT | /v1/edges/{id}/plugins/{name} | edge:plugin | enable/disable + tune a plugin |
| GET | /v1/integrations/plugin-counts | any | global plugin enable/disable counts (for the homepage tile) |
device (host entity, decoupled from tunnel state)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/devices | any | list host devices |
| GET | /v1/devices/{id} | any | get device detail |
| PATCH | /v1/devices/{id} | device:* | update display name, tags |
| DELETE | /v1/devices/{id} | device:* | remove device |
| PATCH | /v1/devices/{id}/roles | device:* | assign roles (db, web, cache...) |
| GET | /v1/devices/{id}/edges | any | edges currently representing this device |
| GET | /v1/devices/{device_id}/shell | webshell | open a WebSSH stream (websocket upgrade) |
topology (typed CMDB)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/topology/node-types | any | list node-type schemas |
| POST | /v1/topology/node-types | topology:* | create node type |
| GET | /v1/topology/node-types/{name} | any | get one node type |
| DELETE | /v1/topology/node-types/{name} | topology:* | remove node type |
| GET | /v1/topology/nodes | any | list nodes (filter by type, tag) |
| POST | /v1/topology/nodes | topology:* | create node |
| GET | /v1/topology/nodes/{id} | any | get node |
| PATCH | /v1/topology/nodes/{id} | topology:* | update node |
| DELETE | /v1/topology/nodes/{id} | topology:* | remove node |
| GET | /v1/topology/relation-types | any | list relation-type schemas |
| POST | /v1/topology/relation-types | topology:* | create relation type |
| GET | /v1/topology/relation-types/{name} | any | get one relation type |
| DELETE | /v1/topology/relation-types/{name} | topology:* | remove relation type |
| GET | /v1/topology/relations | any | list edges (relations) |
| POST | /v1/topology/relations | topology:* | create relation |
| GET | /v1/topology/relations/{id} | any | get relation |
| PATCH | /v1/topology/relations/{id} | topology:* | update relation |
| DELETE | /v1/topology/relations/{id} | topology:* | remove relation |
alert (rules, incidents, channels)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/alert-rules | any | list rules |
| POST | /v1/alert-rules | alert:* | create rule |
| GET | /v1/alert-rules/{id} | any | get rule |
| PUT | /v1/alert-rules/{id} | alert:* | replace rule |
| DELETE | /v1/alert-rules/{id} | alert:* | remove rule |
| POST | /v1/alert-rules/{id}/enabled | alert:* | flip enabled flag |
| POST | /v1/alert-rules/preview | alert:* | dry-run a rule definition against current data |
| GET | /v1/alerts/incidents | any | list incidents (filters: status, severity, scope) |
| GET | /v1/alerts/incidents/{id} | any | get incident |
| GET | /v1/alerts/incidents/{id}/events | any | event timeline |
| POST | /v1/alerts/incidents/{id}/ack | any | acknowledge |
| POST | /v1/alerts/incidents/{id}/resolve | any | mark resolved |
| POST | /v1/alerts/incidents/{id}/silence | any | silence for N hours |
| GET | /v1/alerts/incidents/{id}/investigation | any | get the AI-generated investigation report |
| POST | /v1/alerts/incidents/{id}/investigation | any | trigger or re-run the investigation |
| GET | /v1/alerts/runtime-info | any | evaluator pace + last cycle stats |
| GET | /v1/notification-channels | any | list channels |
| POST | /v1/notification-channels | channel:* | create channel |
| GET | /v1/notification-channels/{id} | any | get channel |
| PUT | /v1/notification-channels/{id} | channel:* | replace channel |
| DELETE | /v1/notification-channels/{id} | channel:* | remove channel |
| POST | /v1/notification-channels/{id}/test | channel:* | send a synthetic notification |
See Alert rule schema for the JSON shape of a rule.
aiops (chat, agents, models)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/agents | any | list agent personas |
| GET | /v1/agents/{name} | any | get persona detail |
| DELETE | /v1/agents/{name} | agent:* | delete a built-in / disk persona (rare; usually only custom deletable) |
| POST | /v1/agents/custom | agent:* | create a user-defined persona |
| PATCH | /v1/agents/custom/{name} | agent:* | update user persona |
| DELETE | /v1/agents/custom/{name} | agent:* | delete user persona |
| GET | /v1/chat/sessions | any | list sessions |
| POST | /v1/chat/sessions | any | create session |
| PATCH | /v1/chat/sessions/{id} | any | rename / tag a session |
| DELETE | /v1/chat/sessions/{id} | any | delete session |
| GET | /v1/chat/sessions/{id}/messages | any | message history |
| POST | /v1/chat/sessions/{id}/messages | any | send a message (non-streaming, returns final reply) |
| POST | /v1/chat/sessions/{id}/messages/stream | any | send a message (SSE stream of token + tool-call events) |
| GET | /v1/aiops/models | any | available providers + models (gated by configured API keys) |
| POST | /v1/aiops/query-translate | any | LLM-assisted PromQL / LogQL / TraceQL composition |
| GET | /v1/aiops/mentions/search | any | autocomplete for @edge, @device, @dashboard mentions |
| GET | /v1/usage/today | any | token usage for the current UTC day |
See Agent persona format for the markdown frontmatter shape.
knowledge (RAG, vault, repos, uploads)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/knowledge/docs | any | list documents (tree) |
| POST | /v1/knowledge/docs | knowledge:* | create document |
| GET | /v1/knowledge/docs/{id} | any | get document |
| PATCH | /v1/knowledge/docs/{id} | knowledge:* | edit document body |
| PATCH | /v1/knowledge/docs/{id}/move | knowledge:* | move to another path |
| DELETE | /v1/knowledge/docs/{id} | knowledge:* | remove document |
| GET | /v1/knowledge/paths | any | list path nodes (for the tree) |
| GET | /v1/knowledge/repos | any | list Git repos |
| POST | /v1/knowledge/repos | knowledge:* | register a repo |
| DELETE | /v1/knowledge/repos/{id} | knowledge:* | remove repo |
| POST | /v1/knowledge/repos/{id}/sync | knowledge:* | trigger a re-sync |
| POST | /v1/knowledge/upload | knowledge:* | upload .md / .txt / .pdf / .docx (parsed via docextract) |
| GET | /v1/knowledge/search | any | RAG query (returns chunks + scores) |
| POST | /v1/knowledge/vault/sync | knowledge:* | re-pull built-in vault from GitHub |
| GET | /v1/knowledge/ssh-identities | knowledge:* | list SSH keys for Git auth |
| POST | /v1/knowledge/ssh-identities | knowledge:* | register an existing SSH key |
| POST | /v1/knowledge/ssh-identities/generate | knowledge:* | generate a new keypair (private key never leaves server) |
| PATCH | /v1/knowledge/ssh-identities/{id} | knowledge:* | edit identity (name, comment) |
| DELETE | /v1/knowledge/ssh-identities/{id} | knowledge:* | remove identity |
skill (toolbag introspection)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/skills | any | list skills (manager-scope + edge-scope) |
| GET | /v1/skills/{key} | any | get skill detail (schema, description, scope, class) |
| POST | /v1/skills/{key}/execute | skill:* | direct skill execution (testing / debugging) |
See Skill manifest for the on-disk skill.json shape.
logs / traces (read-only proxies)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/logs/query_range | any | proxied LogQL query_range |
| GET | /v1/logs/labels | any | proxied label-names |
| GET | /v1/logs/labels/{name}/values | any | proxied label-values |
| GET | /v1/traces/search | any | proxied TraceQL /api/search |
| GET | /v1/traces/{trace_id} | any | one trace by ID |
| GET | /v1/traces/tags/{tag}/values | any | proxied /api/search/tag/.../values |
monitor (dashboards / panels)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/monitor/panels | any | list panels |
| POST | /v1/monitor/panels | monitor:* | create panel |
| PATCH | /v1/monitor/panels/{id} | monitor:* | edit panel |
| DELETE | /v1/monitor/panels/{id} | monitor:* | remove panel |
| GET | /v1/observability/dashboards/{uid} | any | render-ready Grafana dashboard JSON |
metric (per-edge metric snapshot)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/edges/{id}/metrics | any | latest closed-set host metric snapshot |
prometheus (admin)
| Method | Path | Role | Description |
|---|---|---|---|
| POST | /v1/prometheus/launch | admin | (re-)launch the embedded Prometheus |
| POST | /v1/prometheus/query_range | any | LLM-tool-facing query_range (returns normalised matrix) |
imbridge (chat surfaces — Slack / Telegram / Lark / DingTalk / WeCom)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/im/apps | any | list connected IM apps |
| POST | /v1/im/apps | im:* | register IM app |
| GET | /v1/im/apps/{id} | any | get app |
| PUT | /v1/im/apps/{id} | im:* | update app |
| DELETE | /v1/im/apps/{id} | im:* | remove app |
| POST | /v1/im/apps/{id}/reveal | admin | reveal masked secrets |
marketplace (skill packs)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/marketplace/registries | any | list configured registries |
| GET | /v1/marketplace/installed | any | list installed packs |
| POST | /v1/marketplace/install | marketplace:* | install pack from a registry |
| DELETE | /v1/marketplace/installed/{pack_id} | marketplace:* | uninstall pack |
setting (system settings: integrations, defaults, secrets)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/system-settings | any | list visible settings |
| PUT | /v1/system-settings/{category}/{key} | admin | upsert setting |
| DELETE | /v1/system-settings/{category}/{key} | admin | remove setting |
| GET | /v1/system-settings/{category}/{key}/reveal | admin | reveal masked secret |
integration (connectivity tests)
| Method | Path | Role | Description |
|---|---|---|---|
| POST | /v1/integrations/grafana/sync | admin | sync dashboards + datasources |
| POST | /v1/integrations/grafana/test | admin | test Grafana connection |
| POST | /v1/integrations/llm/invalidate | admin | invalidate cached LLM client (forces re-read of API keys) |
| POST | /v1/integrations/loki/test | admin | test Loki connection |
| POST | /v1/integrations/prom/test | admin | test Prometheus connection |
| POST | /v1/integrations/tempo/test | admin | test Tempo connection |
| POST | /v1/integrations/websearch/test | admin | test SearXNG / web-search backend |
webshell (interactive shell over the tunnel)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/devices/{device_id}/shell | webshell | open WebSocket-upgraded SSH stream |
| GET | /v1/webshell/sessions | any | list active sessions |
| DELETE | /v1/webshell/sessions/{id} | webshell | kill a session |
audit (admin log)
| Method | Path | Role | Description |
|---|---|---|---|
| GET | /v1/admin/audit-logs | admin | tenant-wide audit trail (HLD-010) |
Pagination
List endpoints use opaque cursors:
GET /v1/edges?limit=50&cursor=eyJpZCI6MTAwMH0The response carries {"items":[...], "next_cursor":"...", "total":...}. next_cursor is empty on the last page.
Rate limits
There are no global rate limits in the open-source build. The LLM budget gate (ONGRID_LLM_DAILY_TOKEN_LIMIT) bounds chat traffic — every other endpoint depends on whatever you put in front of the manager (nginx, your own gateway).
Versioning
GET /v1/version returns {"manager_version":"vX.Y.Z"}. The SPA reads this and flags edges whose agent version drifts from the manager. Use it for upgrade tooling.
See also
- Environment variables — what controls the API's behaviour.
- Alert rule schema — request body for
/v1/alert-rules. - Skill manifest — request body for
/v1/skillsand marketplace install. - Agent persona format — request body for
/v1/agents/custom.