{
  "topic": "openapi",
  "path": [
    "openapi"
  ],
  "title": "openapi — OpenAPI 3 spec and discovery endpoints",
  "synopsis": "cyoda-go generates its OpenAPI 3.1 specification from the embedded `api/openapi.yaml` file compiled into the binary at build time. The spec is served at `/openapi.json` with runtime-patched server URLs. The Scalar API Reference UI is served at `/docs` and loads the spec from `/openapi.json`.",
  "body": "# openapi\n\n## NAME\n\nopenapi — OpenAPI 3.1 specification and discovery endpoints for the cyoda-go REST API.\n\n## SYNOPSIS\n\n```\nGET /openapi.json\nGET /docs\nGET {CYODA_CONTEXT_PATH}/help\nGET {CYODA_CONTEXT_PATH}/help/{topic}\n```\n\nDiscovery endpoints are served at the root of the HTTP listener (port `CYODA_HTTP_PORT`, default 8080). They are mounted outside `CYODA_CONTEXT_PATH` — no prefix is applied.\n\n## DESCRIPTION\n\ncyoda-go generates its OpenAPI 3.1 specification from the embedded `api/openapi.yaml` file compiled into the binary at build time. The spec is served at `/openapi.json` with runtime-patched server URLs. The Scalar API Reference UI is served at `/docs` and loads the spec from `/openapi.json`.\n\nThe `/openapi.json` and `/docs` endpoints require no authentication. The help endpoints (`/help`, `/help/{topic}`) also require no authentication.\n\n## DISCOVERY ENDPOINTS\n\n**GET /openapi.json**\n\nReturns the OpenAPI 3.1 specification as JSON. The `servers` array is overridden at request time to reflect the actual runtime host and `CYODA_CONTEXT_PATH`. The scheme (`http` or `https`) is derived from whether the incoming connection is TLS.\n\nResponse: `200 OK`, `application/json`.\n\nThe spec itself sets `info.version` to `\"1.0\"` (a fixed spec version, not the binary version). The binary version is reported separately in the `GET /help` payload under the `version` field.\n\n**GET /docs**\n\nReturns an HTML page embedding the Scalar API Reference UI. The UI loads the spec from `/openapi.json` and provides an interactive browser. No JavaScript execution is required on the server side — the HTML page references the Scalar CDN script.\n\nResponse: `200 OK`, `text/html; charset=utf-8`.\n\n**GET {CYODA_CONTEXT_PATH}/help**\n\nReturns the full help topic tree as JSON. The response includes the binary version string and an array of all topic descriptors.\n\nResponse: `200 OK`, `application/json`:\n\n```json\n{\n  \"schema\": 1,\n  \"version\": \"dev\",\n  \"topics\": [\n    {\n      \"topic\": \"quickstart\",\n      \"title\": \"cyoda quickstart — minimum invocations\",\n      \"stability\": \"stable\",\n      \"tagline\": \"minimum commands to run a cyoda-go server.\",\n      \"see_also\": [\"cli\", \"config\"]\n    }\n  ]\n}\n```\n\n**GET {CYODA_CONTEXT_PATH}/help/{topic}**\n\nReturns a single help topic descriptor by dotted path. The `topic` path segment uses dots as separators (e.g. `config.database`, `errors.MODEL_NOT_FOUND`). Topics are resolved via the embedded help tree.\n\nResponse: `200 OK`, `application/json` — same shape as a single element of the `topics` array above, with the addition of a `body` field containing the full Markdown content.\n\n`404 HELP_TOPIC_NOT_FOUND` when the topic path does not exist.\n`400 BAD_REQUEST` when the topic path contains disallowed characters (only `A-Za-z0-9`, `.`, `_`, `-` are allowed; no leading/trailing dots or hyphens).\n\n## SPEC SHAPE\n\nThe spec covers 67 paths across these tag groups:\n\n- **Entity Management** — create, update, delete, transition, and stats endpoints under `/entity/`\n- **Entity Model** — model import, export, lock, unlock, delete, changeLevel, and workflow under `/model/`\n- **Search** — snapshot and direct search under `/search/`\n- **User, Account** — account info and subscriptions under `/account/`\n- **User, Machine** — M2M client management under `/clients/`\n- **Entity, Audit** — audit log retrieval under `/audit/`\n- **Messaging** — message CRUD under `/message/`\n- **IAM** — OAuth token, key management, OIDC providers under `/oauth/`\n- **SQL Schema** — SQL schema generation and management under `/sql/schema/`\n- **Platform API** — stream-data operations under `/platform-api/stream-data/`\n\nAll paths in the spec are relative to the `servers[0].url`, which is set at runtime to `{scheme}://{host}{CYODA_CONTEXT_PATH}`. The default context path is `/api`, so `GET /entity/{entityId}` is served at `http://localhost:8080/api/entity/{entityId}`.\n\n## AUTHENTICATION\n\nThe spec declares one security scheme:\n\n```yaml\ncomponents:\n  securitySchemes:\n    bearerAuth:\n      type: http\n      scheme: bearer\n      description: >-\n        Authorization header: `Bearer <access_token>`\n```\n\nGlobal security is applied to all operations: `security: [{bearerAuth: []}]`. Discovery endpoints (`/openapi.json`, `/docs`) and help endpoints are not part of the spec and carry no security requirement.\n\nWhen `CYODA_IAM_MODE=mock`, the server accepts requests without a token. When `CYODA_IAM_MODE=jwt`, a valid JWT Bearer token is required on all protected endpoints.\n\n## CONTEXT PATH\n\n`CYODA_CONTEXT_PATH` (default `/api`) is the prefix applied to all API routes. It affects:\n\n- The `servers[0].url` field in the served `/openapi.json` response.\n- All route registrations for entity, model, search, audit, messaging, OAuth, and SQL endpoints.\n- The help route prefix (`{CYODA_CONTEXT_PATH}/help` and `{CYODA_CONTEXT_PATH}/help/{topic}`).\n\nThe discovery routes `/openapi.json` and `/docs` are always at the root — `CYODA_CONTEXT_PATH` does not prefix them.\n\nSetting `CYODA_CONTEXT_PATH=` (empty string) mounts all routes at root with no prefix.\n\n## VERSIONING\n\nThe spec `info.version` field is `\"1.0\"` — a fixed spec format version. It does not track the binary version.\n\nThe binary version is injected at build time via `-ldflags` and reported in:\n- The startup banner printed to stderr.\n- The `GET {CYODA_CONTEXT_PATH}/help` JSON payload's `version` field.\n\n## ERRORS\n\nThe REST API uses `application/problem+json` (RFC 9457 Problem Details) error responses. See `errors` for the canonical shape and the full error code catalogue.\n\nError response shape (4xx example):\n\n```json\n{\n  \"type\": \"about:blank\",\n  \"title\": \"Not Found\",\n  \"status\": 404,\n  \"detail\": \"MODEL_NOT_FOUND: model nobel-prize:1 not found\",\n  \"instance\": \"/api/model/nobel-prize/1\",\n  \"properties\": {\n    \"errorCode\": \"MODEL_NOT_FOUND\",\n    \"retryable\": false\n  }\n}\n```\n\nError response shape (5xx example):\n\n```json\n{\n  \"type\": \"about:blank\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"SERVER_ERROR: internal error [ticket: 3fa85f64-5717-4562-b3fc-2c963f66afa6]\",\n  \"instance\": \"/api/entity/abc\",\n  \"ticket\": \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n  \"properties\": {\n    \"errorCode\": \"SERVER_ERROR\"\n  }\n}\n```\n\n`CYODA_ERROR_RESPONSE_MODE=sanitized` (default) suppresses internal detail from 5xx `detail` fields. `CYODA_ERROR_RESPONSE_MODE=verbose` includes full error detail — for development environments only.\n\n## EXAMPLES\n\n**Fetch the OpenAPI spec:**\n\n```\ncurl -s http://localhost:8080/openapi.json | jq '.info'\n```\n\n**Fetch with custom context path:**\n\n```\nCYODA_CONTEXT_PATH=/v1 \\\ncurl -s http://localhost:8080/openapi.json | jq '.servers'\n```\n\nResponse:\n```json\n[{\"url\": \"http://localhost:8080/v1\"}]\n```\n\n**Open the interactive UI:**\n\n```\ncurl -s -o /dev/null -w \"%{http_code}\" http://localhost:8080/docs\n```\n\n**Fetch the full help topic tree:**\n\n```\ncurl -s http://localhost:8080/api/help | jq '.topics[].topic'\n```\n\n**Fetch a specific help topic:**\n\n```\ncurl -s http://localhost:8080/api/help/models | jq '.title'\n```\n\n**Fetch the spec from a Docker container:**\n\n```\ndocker run --rm \\\n  -p 127.0.0.1:8080:8080 \\\n  -e CYODA_STORAGE_BACKEND=memory \\\n  ghcr.io/cyoda-platform/cyoda:latest &\nsleep 2\ncurl -s http://localhost:8080/openapi.json | jq '.paths | keys | length'\n```\n\n## ACTION DETAILS\n\n- `cyoda help openapi json` — emit the embedded OpenAPI spec as JSON to stdout\n- `cyoda help openapi yaml` — emit the embedded OpenAPI spec as YAML to stdout\n- `cyoda help openapi tags` — list every tag in the spec as `<slug>  <canonical name>` pairs (tabular, sorted by slug)\n- `cyoda help openapi <slug>` — emit a standalone OpenAPI 3.1 document scoped to the named tag; paths filtered to operations carrying that tag, components pruned to only the transitively-referenced members. Pass `--format=yaml` to emit YAML instead of the default JSON. Discover valid slugs via `cyoda help openapi tags`. Unknown slugs exit 2 with the full valid-slug list in the error.\n\nThe emitted spec is the binary's compile-time baseline. The `servers` array reflects whatever is embedded at build time; the running server's HTTP endpoint (`GET /openapi.json`) rewrites `servers` per request, but the CLI does not.\n\nPer-tag filtering is useful for AI agents and downstream tooling that only need the slice of the API corresponding to one concern (e.g. just `entity-management` or just `search`) — the pruned spec is typically 3-5× smaller than the full spec and is still a valid standalone OpenAPI 3.1 document (every `$ref` resolves within its own `components`).\n\n## SEE ALSO\n\n- crud\n- models\n- search\n- workflows\n- errors\n- config.auth\n- cli.serve\n",
  "sections": [
    {
      "name": "NAME",
      "body": "openapi — OpenAPI 3.1 specification and discovery endpoints for the cyoda-go REST API."
    },
    {
      "name": "SYNOPSIS",
      "body": "```\nGET /openapi.json\nGET /docs\nGET {CYODA_CONTEXT_PATH}/help\nGET {CYODA_CONTEXT_PATH}/help/{topic}\n```\n\nDiscovery endpoints are served at the root of the HTTP listener (port `CYODA_HTTP_PORT`, default 8080). They are mounted outside `CYODA_CONTEXT_PATH` — no prefix is applied."
    },
    {
      "name": "DESCRIPTION",
      "body": "cyoda-go generates its OpenAPI 3.1 specification from the embedded `api/openapi.yaml` file compiled into the binary at build time. The spec is served at `/openapi.json` with runtime-patched server URLs. The Scalar API Reference UI is served at `/docs` and loads the spec from `/openapi.json`.\n\nThe `/openapi.json` and `/docs` endpoints require no authentication. The help endpoints (`/help`, `/help/{topic}`) also require no authentication."
    },
    {
      "name": "DISCOVERY ENDPOINTS",
      "body": "**GET /openapi.json**\n\nReturns the OpenAPI 3.1 specification as JSON. The `servers` array is overridden at request time to reflect the actual runtime host and `CYODA_CONTEXT_PATH`. The scheme (`http` or `https`) is derived from whether the incoming connection is TLS.\n\nResponse: `200 OK`, `application/json`.\n\nThe spec itself sets `info.version` to `\"1.0\"` (a fixed spec version, not the binary version). The binary version is reported separately in the `GET /help` payload under the `version` field.\n\n**GET /docs**\n\nReturns an HTML page embedding the Scalar API Reference UI. The UI loads the spec from `/openapi.json` and provides an interactive browser. No JavaScript execution is required on the server side — the HTML page references the Scalar CDN script.\n\nResponse: `200 OK`, `text/html; charset=utf-8`.\n\n**GET {CYODA_CONTEXT_PATH}/help**\n\nReturns the full help topic tree as JSON. The response includes the binary version string and an array of all topic descriptors.\n\nResponse: `200 OK`, `application/json`:\n\n```json\n{\n  \"schema\": 1,\n  \"version\": \"dev\",\n  \"topics\": [\n    {\n      \"topic\": \"quickstart\",\n      \"title\": \"cyoda quickstart — minimum invocations\",\n      \"stability\": \"stable\",\n      \"tagline\": \"minimum commands to run a cyoda-go server.\",\n      \"see_also\": [\"cli\", \"config\"]\n    }\n  ]\n}\n```\n\n**GET {CYODA_CONTEXT_PATH}/help/{topic}**\n\nReturns a single help topic descriptor by dotted path. The `topic` path segment uses dots as separators (e.g. `config.database`, `errors.MODEL_NOT_FOUND`). Topics are resolved via the embedded help tree.\n\nResponse: `200 OK`, `application/json` — same shape as a single element of the `topics` array above, with the addition of a `body` field containing the full Markdown content.\n\n`404 HELP_TOPIC_NOT_FOUND` when the topic path does not exist.\n`400 BAD_REQUEST` when the topic path contains disallowed characters (only `A-Za-z0-9`, `.`, `_`, `-` are allowed; no leading/trailing dots or hyphens)."
    },
    {
      "name": "SPEC SHAPE",
      "body": "The spec covers 67 paths across these tag groups:\n\n- **Entity Management** — create, update, delete, transition, and stats endpoints under `/entity/`\n- **Entity Model** — model import, export, lock, unlock, delete, changeLevel, and workflow under `/model/`\n- **Search** — snapshot and direct search under `/search/`\n- **User, Account** — account info and subscriptions under `/account/`\n- **User, Machine** — M2M client management under `/clients/`\n- **Entity, Audit** — audit log retrieval under `/audit/`\n- **Messaging** — message CRUD under `/message/`\n- **IAM** — OAuth token, key management, OIDC providers under `/oauth/`\n- **SQL Schema** — SQL schema generation and management under `/sql/schema/`\n- **Platform API** — stream-data operations under `/platform-api/stream-data/`\n\nAll paths in the spec are relative to the `servers[0].url`, which is set at runtime to `{scheme}://{host}{CYODA_CONTEXT_PATH}`. The default context path is `/api`, so `GET /entity/{entityId}` is served at `http://localhost:8080/api/entity/{entityId}`."
    },
    {
      "name": "AUTHENTICATION",
      "body": "The spec declares one security scheme:\n\n```yaml\ncomponents:\n  securitySchemes:\n    bearerAuth:\n      type: http\n      scheme: bearer\n      description: >-\n        Authorization header: `Bearer <access_token>`\n```\n\nGlobal security is applied to all operations: `security: [{bearerAuth: []}]`. Discovery endpoints (`/openapi.json`, `/docs`) and help endpoints are not part of the spec and carry no security requirement.\n\nWhen `CYODA_IAM_MODE=mock`, the server accepts requests without a token. When `CYODA_IAM_MODE=jwt`, a valid JWT Bearer token is required on all protected endpoints."
    },
    {
      "name": "CONTEXT PATH",
      "body": "`CYODA_CONTEXT_PATH` (default `/api`) is the prefix applied to all API routes. It affects:\n\n- The `servers[0].url` field in the served `/openapi.json` response.\n- All route registrations for entity, model, search, audit, messaging, OAuth, and SQL endpoints.\n- The help route prefix (`{CYODA_CONTEXT_PATH}/help` and `{CYODA_CONTEXT_PATH}/help/{topic}`).\n\nThe discovery routes `/openapi.json` and `/docs` are always at the root — `CYODA_CONTEXT_PATH` does not prefix them.\n\nSetting `CYODA_CONTEXT_PATH=` (empty string) mounts all routes at root with no prefix."
    },
    {
      "name": "VERSIONING",
      "body": "The spec `info.version` field is `\"1.0\"` — a fixed spec format version. It does not track the binary version.\n\nThe binary version is injected at build time via `-ldflags` and reported in:\n- The startup banner printed to stderr.\n- The `GET {CYODA_CONTEXT_PATH}/help` JSON payload's `version` field."
    },
    {
      "name": "ERRORS",
      "body": "The REST API uses `application/problem+json` (RFC 9457 Problem Details) error responses. See `errors` for the canonical shape and the full error code catalogue.\n\nError response shape (4xx example):\n\n```json\n{\n  \"type\": \"about:blank\",\n  \"title\": \"Not Found\",\n  \"status\": 404,\n  \"detail\": \"MODEL_NOT_FOUND: model nobel-prize:1 not found\",\n  \"instance\": \"/api/model/nobel-prize/1\",\n  \"properties\": {\n    \"errorCode\": \"MODEL_NOT_FOUND\",\n    \"retryable\": false\n  }\n}\n```\n\nError response shape (5xx example):\n\n```json\n{\n  \"type\": \"about:blank\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"SERVER_ERROR: internal error [ticket: 3fa85f64-5717-4562-b3fc-2c963f66afa6]\",\n  \"instance\": \"/api/entity/abc\",\n  \"ticket\": \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n  \"properties\": {\n    \"errorCode\": \"SERVER_ERROR\"\n  }\n}\n```\n\n`CYODA_ERROR_RESPONSE_MODE=sanitized` (default) suppresses internal detail from 5xx `detail` fields. `CYODA_ERROR_RESPONSE_MODE=verbose` includes full error detail — for development environments only."
    },
    {
      "name": "EXAMPLES",
      "body": "**Fetch the OpenAPI spec:**\n\n```\ncurl -s http://localhost:8080/openapi.json | jq '.info'\n```\n\n**Fetch with custom context path:**\n\n```\nCYODA_CONTEXT_PATH=/v1 \\\ncurl -s http://localhost:8080/openapi.json | jq '.servers'\n```\n\nResponse:\n```json\n[{\"url\": \"http://localhost:8080/v1\"}]\n```\n\n**Open the interactive UI:**\n\n```\ncurl -s -o /dev/null -w \"%{http_code}\" http://localhost:8080/docs\n```\n\n**Fetch the full help topic tree:**\n\n```\ncurl -s http://localhost:8080/api/help | jq '.topics[].topic'\n```\n\n**Fetch a specific help topic:**\n\n```\ncurl -s http://localhost:8080/api/help/models | jq '.title'\n```\n\n**Fetch the spec from a Docker container:**\n\n```\ndocker run --rm \\\n  -p 127.0.0.1:8080:8080 \\\n  -e CYODA_STORAGE_BACKEND=memory \\\n  ghcr.io/cyoda-platform/cyoda:latest &\nsleep 2\ncurl -s http://localhost:8080/openapi.json | jq '.paths | keys | length'\n```"
    },
    {
      "name": "ACTION DETAILS",
      "body": "- `cyoda help openapi json` — emit the embedded OpenAPI spec as JSON to stdout\n- `cyoda help openapi yaml` — emit the embedded OpenAPI spec as YAML to stdout\n- `cyoda help openapi tags` — list every tag in the spec as `<slug>  <canonical name>` pairs (tabular, sorted by slug)\n- `cyoda help openapi <slug>` — emit a standalone OpenAPI 3.1 document scoped to the named tag; paths filtered to operations carrying that tag, components pruned to only the transitively-referenced members. Pass `--format=yaml` to emit YAML instead of the default JSON. Discover valid slugs via `cyoda help openapi tags`. Unknown slugs exit 2 with the full valid-slug list in the error.\n\nThe emitted spec is the binary's compile-time baseline. The `servers` array reflects whatever is embedded at build time; the running server's HTTP endpoint (`GET /openapi.json`) rewrites `servers` per request, but the CLI does not.\n\nPer-tag filtering is useful for AI agents and downstream tooling that only need the slice of the API corresponding to one concern (e.g. just `entity-management` or just `search`) — the pruned spec is typically 3-5× smaller than the full spec and is still a valid standalone OpenAPI 3.1 document (every `$ref` resolves within its own `components`)."
    },
    {
      "name": "SEE ALSO",
      "body": "- crud\n- models\n- search\n- workflows\n- errors\n- config.auth\n- cli.serve"
    }
  ],
  "see_also": [
    "crud",
    "models",
    "search",
    "workflows",
    "errors",
    "config.auth",
    "cli.serve"
  ],
  "stability": "stable",
  "actions": [
    "json",
    "tags",
    "yaml"
  ]
}
