API guide
Everything Yagra does is driven through one REST API. This page covers how to authenticate against it and the conventions every endpoint follows.
The per-endpoint details live in the generated API reference, and AI assistants get their own surface, the MCP server.
The northbound API
Section titled “The northbound API”The API is served by core on the API port (8080 in the bundled compose files), with every path
under the /api/v1 prefix — about 318 endpoints. The reference is
generated from the OpenAPI document and is the count that cannot go stale.
Two unversioned health probes sit outside that prefix: GET /healthz (liveness) and GET /readyz
(readiness). In a high-availability pair only the leader answers 200 on /readyz, so a load balancer
can route on it.
Everything the WebUI does goes through this same API. There is no private backchannel. Every
inventory screen, dashboard, alert action, and settings page is a sequence of /api/v1 calls, so
anything you can see or do in the browser you can automate.
When in doubt about how to do something programmatically, do it once in the WebUI with the browser’s network tab open. That shows the exact requests.
Authentication
Section titled “Authentication”Two credentials authenticate this API, both sent as Authorization: Bearer <token>:
- a session token, exchanged for a username and password — short-lived, and what the WebUI uses;
- an API token (
yat_…, minted under Settings ▸ API tokens) — long-lived, for unattended clients. Use this one for scripts, CI jobs and integrations.
Session tokens
Section titled “Session tokens”Exchange a username and password for a bearer session token at POST /api/v1/auth/login:
curl -s http://<yagra-host>:8080/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "your-password"}'{ "token": "<session-token>", "role": "admin" }Send that token on every subsequent request:
curl -s http://<yagra-host>:8080/api/v1/nodes \ -H "Authorization: Bearer <session-token>"The response also carries the account’s role, so a client knows up front what it will be allowed to do.
Login is rate-limited per account and globally: too many attempts answer 429 with a Retry-After
header. POST /api/v1/auth/logout revokes the token.
API tokens
Section titled “API tokens”For anything unattended, mint an API token instead of scripting a login. An admin creates one under Settings ▸ API tokens, and the raw value is shown once and never again. Send it exactly like a session token:
curl -s http://<yagra-host>:8080/api/v1/nodes \ -H "Authorization: Bearer yat_…"Four things about a token are worth knowing before you issue one:
-
It names the surfaces it may be used at. A token reaches this REST API only if it was created with the
restsurface.Tokens created before that field existed carry
mcpalone and answer401here. An upgrade never widens what an existing credential can do. -
It acts as an account. Every token has an owner. Its effective role is the lower of the token’s role and the owner’s current role, so demoting the account narrows the token immediately, and disabling or deleting the account revokes it.
Prefer a service account as the owner (see Users & SSO), so an integration does not depend on the person who set it up.
-
It cannot administer users.
POST /api/v1/users, the API-token endpoints themselves, and anything else behind the user-management permission answer403 token_not_permittedto a token, whatever its role. A credential that could mint its own successor would survive revoking the original. -
It has no interactive identity. Endpoints that mean “the signed-in account” —
GET /api/v1/auth/meand the personal dashboard — answer403 session_required.
An optional expiry (expires_at) is offered when creating one, and omitting it still means no
expiry. Revoke a token from the same page at any time. Revocation takes effect immediately.
A few endpoints are deliberately unauthenticated, because a client needs them before it can log in. None of them reveal inventory, configuration, or state:
| Endpoint | Returns |
|---|---|
GET /api/v1/version |
The running core version |
GET /api/v1/config |
Client bootstrap flags (whether auth, SSO, and AI analysis are available) — no secrets |
GET /api/v1/openapi.json |
The generated OpenAPI document (below) |
GET /healthz, GET /readyz |
Liveness and readiness probes |
If the deployment runs with the public-dashboard option, read endpoints open up without a token. Every write stays authenticated.
Conventions
Section titled “Conventions”The whole surface follows one set of rules, so what you learn on one endpoint carries to the rest:
-
JSON everywhere. Request bodies and responses are JSON. Set
Content-Type: application/jsonwhen sending a body. -
Creation returns
201with the new resource’s id:{"id": "<uuid>"}. -
Deletion returns
204 No Content. No body, and deletes are idempotent where that is safe. -
Errors are typed. Every failure renders the same envelope:
{ "error": { "code": "invalid_filter", "message": "…" } }The
codeis stable and machine-readable — branch on it, not on the message. Themessageis operator-safe prose and never carries internal error text.Status codes follow the usual meanings:
400malformed input,401unauthenticated,403authenticated but not permitted,404no such resource,409conflict,429throttled (with aRetry-Afterheader),502an upstream store or provider failed (distinct from500, a fault in Yagra itself), and503an optional subsystem this deployment has not configured. -
Authentication is checked before availability. An endpoint whose subsystem is unconfigured answers
503only to a caller who is already authenticated and permitted. An anonymous request gets401regardless.This is deliberate: the deployment does not disclose which subsystems it runs to a caller holding no credential. (Before v0.1.19 the two checks ran in the other order on most endpoints.)
-
Large lists are enveloped and capped. A listing that could grow unbounded returns
{"items": [...], "total": <n>, "truncated": <bool>}rather than a bare array.For example,
GET /api/v1/thresholdsreturns at most 500 rules per request, withtotalcarrying the unfiltered count. A?limit=parameter can narrow a cap, never widen it. -
Timestamps are RFC 3339 strings (
2026-08-01T09:30:00Z), in responses and in query parameters that take a time.
Roles and permissions
Section titled “Roles and permissions”Every request is authorized per endpoint by the role the token carries:
- Viewer — read-only: inventory, metrics, alerts, events, flows.
- Operator — Viewer plus incident response: acknowledge and mute alerts, open and close maintenance windows, run Troubleshoot analyses and AI root-cause explanations.
- Admin — full control: nodes, profiles, thresholds, credentials, users, and the audit log.
A request with a valid token but an insufficient role answers 403, distinguishable from the 401
an unauthenticated request gets.
State-changing requests are recorded in the audit log automatically, except
PUT /api/v1/preferences, which saves one account’s own WebUI preferences. The full role and permission
model, including single sign-on, is described in Users & SSO.
The OpenAPI document
Section titled “The OpenAPI document”The API publishes its own contract at GET /api/v1/openapi.json: an OpenAPI 3.1 document
covering every path, query parameter, request body, response shape, and error code.
It is generated from the handlers themselves, so it describes what the server actually does and cannot drift from the code. The WebUI’s own types and API client are generated from this same document.
It contains no inventory, configuration, or state, so it is served unauthenticated and is identical on every deployment.
Point any OpenAPI client generator at it to get a typed client in your language:
curl -s http://<yagra-host>:8080/api/v1/openapi.json -o yagra-openapi.jsonThe same document is served on this site at /openapi.json, so you can generate
a client without a running deployment.
Browse the reference
Section titled “Browse the reference”The per-endpoint reference — every route with its parameters, bodies, and responses, grouped by domain — is generated from that same document. It lives at /docs/api/reference/, right below this page in the sidebar.
Because it is generated, it is always in step with the release it documents.
Compatibility and changes
Section titled “Compatibility and changes”Behavior changes an API client could notice are always listed in the release notes, each under the version that shipped it. That covers response shapes, status codes, defaults, the meaning of a query parameter, and removed endpoints.
Recent examples of the kind of thing to look for: a bare-array response gaining an envelope and a
cap; delete and create endpoints aligning on 204/201; endpoints nothing called being removed
outright; and a list field being replaced by a more precise one rather than deprecated in place —
nodes.source became nodes.kind in v0.2.1, and the old two-valued field is gone in the same
release.
Skim the notes for the versions you are crossing before upgrading a deployment your automation talks to. See the changelog for where they live.
Regenerating your client from the new deployment’s /api/v1/openapi.json picks up the shape changes
mechanically.
The MCP tool surface
Section titled “The MCP tool surface”For AI assistants there is a second, purpose-built surface: an opt-in MCP server at /mcp.
It exposes monitoring state as tools — mostly read-only queries, plus a few audited actions — so a client like Claude Code or Claude Desktop can answer “which nodes are down?” directly.
It takes the same yat_… API tokens, and a token can name both surfaces or just one. Keeping an
assistant’s credential to mcp alone is the reason that field exists.
It has its own page: MCP server.