Skip to content

Meta HTTP API

This is the reference for the meta-tagged HTTP surface — the process introspection endpoints. All five operations are unauthenticated by design so callers without credentials can discover the health, version, and OpenAPI shape of a deployment before signing in. The wire-contract origin is api/openapi/plexsphere-v1.yaml; this doc is a map, not a duplicate contract.

For the operator and contributor guide to the embedded ReDoc UI (supply-chain story, SHA-256 pinning, Content-Security-Policy posture, bypass-list parity gate, upgrade procedure) see ../../contributing/api-docs.md. For the OpenAPI authoring workflow that produces the spec the UI renders, see ../../contributing/openapi.md. This page is the operation-level reference for the meta tag; the tag-by-tag map of every /v1 surface lives at ./index.md.

Operations

MethodPathOperation IDAuthn requirementCacheableNotes
GET/v1/healthGetHealthnonenoAggregated process health (status + per-dependency checks).
GET/v1/versionGetVersionnoneyes (build-pinned)Build metadata baked at compile time (semver tag, commit SHA, build date).
GET/v1/openapi.jsonGetOpenAPInoneyesThe live OpenAPI document the running binary serves; identical to the YAML at api/openapi/plexsphere-v1.yaml after JSON re-encoding.
GET/v1/docsGetDocsnonenoHTML shell that bootstraps the vendored ReDoc bundle against /v1/openapi.json. Air-gap-friendly — no CDN reach-out.
GET/v1/docs/assets/{asset}GetDocsAssetnonepublic, max-age=3600Serves the vendored ReDoc bundle bytes. The handler matches asset against an allow-list — anything outside it is 404.

Authn / authz bypass

The five operations sit on the authn middleware bypass list at internal/identity/authn/middleware/middleware.go (DefaultBypass()) and the matching authz bypass at internal/authz/middleware/rebac.go. The two lists are kept in lockstep by the parity gate at tests/workspace/middleware_bypass_parity_test.go.

Bypass entries:

  • /v1/health, /v1/version, /v1/openapi.json, /v1/docs — exact-match leaves (a hypothetical /v1/docsx would NOT bypass).
  • /v1/docs/assets/ — trailing-slash family prefix (covers the vendored bundle without listing each filename).

The GetDocsAsset handler enforces a separate allow-list against the asset path parameter so the trailing-slash bypass cannot be turned into a generic file server: the handler matches the literal string redoc.standalone.js and returns a problem+json 404 for anything else.

Path parameters

OperationParameterTypeRequiredNotes
GetDocsAssetasset (path)stringyesBundle asset filename. The handler matches the value against the vendored allow-list (currently just redoc.standalone.js); anything outside the list is 404 not_found.

Schemas

The OpenAPI spec is the authoritative source for field shapes. The schemas this surface uses are:

  • HealthStatus — overall status rollup (ok / degraded / down) plus a checks array of HealthCheck items (name, status, detail).
  • VersionInfo — semver version, git commit, RFC 3339 build date. Baked at compile time; the values are pinned for the lifetime of the running binary.
  • OpenAPI document — a free-form application/json object; clients that need a typed view should fetch the YAML artefact at api/openapi/plexsphere-v1.yaml directly.
  • ReDoc shell + assettext/html and application/javascript respectively; the OpenAPI document cannot describe the framed bytes directly.

For the field-level shapes refer to api/openapi/plexsphere-v1.yaml under components/schemas/.

Security headers

  • /v1/docs carries Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; worker-src 'self' blob:; img-src 'self' data: plus X-Content-Type-Options: nosniff. The 'unsafe-inline' on style-src is a deliberate trade-off — ReDoc's emotion-based style-injection emits dozens of <style> tags at runtime; a per-request nonce or a build-time hash list would always be incomplete. The narrower posture closes the high-impact XSS path without forking ReDoc. See the file-level DECISION block in internal/transport/http/v1/handlers/docs.go for the full rationale.
  • /v1/docs/assets/{asset} carries Cache-Control: public, max-age=3600 plus the same X-Content-Type-Options: nosniff. The bundle is content-addressable via its co-located .sha256 pin and changes only when scripts/update-redoc.sh re-vendors a new version, so a one-hour public cache is the operational sweet spot.

Error taxonomy

All error responses use the shared Problem envelope (application/problem+json). The closed code set this surface emits:

CodeStatusWhereMeaning
not_found404every operationEndpoint not matched OR (for GetDocsAsset) asset is outside the allow-list.
internal500every operationHealth probe panicked, build metadata unavailable, OpenAPI marshal failed, ReDoc shell render failed, or the vendored asset read failed.

The Problem.code field is OPTIONAL on the meta operations — the handler usually emits the canonical not_found / internal codes, but the spec's required fields are only type, title, status, detail, instance. Clients SHOULD fall back to the type identifier when code is absent.

Cross-references