{"openapi":"3.1.0","info":{"title":"Lucis public API","version":"1.0.0","summary":"Read-only public surface for Lucis developer and agent clients.","description":"Lucis is a preventive wellness membership (lucis.life).\n\nThis specification describes the public biomarker catalog, OAuth 2.0 discovery/token endpoints, and RFC RateLimit headers hosted on www.lucis.life.\n\nUnauthenticated GET is supported on the catalog. An optional client_credentials access token with scope `catalog.read` is available; it is not required.\n\nPublic endpoints advertise RateLimit and RateLimit-Policy on every response, and Retry-After on HTTP 429. Quota is best-effort per compute instance. A shared store is not required for the public catalog.\n\nThis API never returns individual member results or other health data. Lucis.life does not currently publish outbound member webhooks or an MCP server.","contact":{"name":"Lucis developer resources","url":"https://www.lucis.life/developers"},"license":{"name":"Lucis website terms","url":"https://www.lucis.life/legal/en/terms"}},"jsonSchemaDialect":"https://spec.openapis.org/oas/3.1/dialect/base","servers":[{"url":"https://www.lucis.life","description":"Lucis website (same-origin public surface, CORS enabled)"}],"tags":[{"name":"Catalog","description":"Public biomarker catalog. Catalog metadata only."},{"name":"Discovery","description":"OpenAPI and OAuth 2.0 authorization-server metadata."},{"name":"OAuth","description":"OAuth 2.0 client_credentials token endpoint (RFC 6749)."}],"security":[],"paths":{"/v1/biomarkers/public":{"servers":[{"url":"https://www.lucis.life","description":"Lucis website (same-origin public surface, CORS enabled)"},{"url":"https://api.lucis.life","description":"Lucis catalog origin (biomarker list only)"}],"get":{"operationId":"getPublicBiomarkerCatalog","tags":["Catalog"],"summary":"List public Lucis biomarkers","description":"Read-only JSON catalog of public panel markers and presentation metadata. No authentication required. Optional Bearer token with scope catalog.read is accepted and ignored for authorization.","security":[{},{"oauth2":["catalog.read"]}],"parameters":[{"name":"template","in":"query","required":false,"description":"Panel variant. Defaults to public-complete-eu on www.lucis.life.","schema":{"type":"string","enum":["public-complete-eu","public-light-eu","public-v2-complete-uk","public-v2-light-uk"],"default":"public-complete-eu"}}],"responses":{"200":{"description":"Public catalog payload.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BiomarkerCatalog"}}}},"400":{"description":"Unknown catalog template or malformed query.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"405":{"description":"Read-only catalog. POST, PUT, PATCH, and DELETE return a rate-limited method-not-allowed problem.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Unexpected server error.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"502":{"description":"Upstream catalog origin failed.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"head":{"operationId":"headPublicBiomarkerCatalog","tags":["Catalog"],"summary":"List public Lucis biomarkers","description":"Read-only JSON catalog of public panel markers and presentation metadata. No authentication required. Optional Bearer token with scope catalog.read is accepted and ignored for authorization.","security":[{},{"oauth2":["catalog.read"]}],"parameters":[{"name":"template","in":"query","required":false,"description":"Panel variant. Defaults to public-complete-eu on www.lucis.life.","schema":{"type":"string","enum":["public-complete-eu","public-light-eu","public-v2-complete-uk","public-v2-light-uk"],"default":"public-complete-eu"}}],"responses":{"200":{"description":"Public catalog payload.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"400":{"description":"Unknown catalog template or malformed query.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"405":{"description":"Read-only catalog. POST, PUT, PATCH, and DELETE return a rate-limited method-not-allowed problem.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}}},"500":{"description":"Unexpected server error.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"502":{"description":"Upstream catalog origin failed.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiJson","tags":["Discovery"],"summary":"Download the Lucis OpenAPI document (JSON)","description":"Returns the Lucis.life OpenAPI 3.1 document describing the public biomarker catalog, OAuth 2.0 token endpoint, typed errors, and rate-limit headers.","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"head":{"operationId":"headOpenApiJson","tags":["Discovery"],"summary":"Download the Lucis OpenAPI document (JSON)","description":"Returns the Lucis.life OpenAPI 3.1 document describing the public biomarker catalog, OAuth 2.0 token endpoint, typed errors, and rate-limit headers.","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}}}}}},"/api/openapi.yaml":{"get":{"operationId":"getOpenApiYaml","tags":["Discovery"],"summary":"Download the Lucis OpenAPI document (YAML)","description":"Returns the same Lucis.life OpenAPI 3.1 document as YAML at /api/openapi.yaml for clients that prefer YAML.","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document as YAML.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/yaml":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"head":{"operationId":"headOpenApiYaml","tags":["Discovery"],"summary":"Download the Lucis OpenAPI document (YAML)","description":"Returns the same Lucis.life OpenAPI 3.1 document as YAML at /api/openapi.yaml for clients that prefer YAML.","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document as YAML.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"getOAuthAuthorizationServerMetadata","tags":["Discovery"],"summary":"OAuth 2.0 authorization server metadata (RFC 8414)","description":"Lucis.life auth docs as RFC 8414 metadata. Public clients use grant_type=client_credentials against POST /oauth/token. The catalog GET does not require a token.","security":[],"responses":{"200":{"description":"Authorization server metadata.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizationServerMetadata"}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"head":{"operationId":"headOAuthAuthorizationServerMetadata","tags":["Discovery"],"summary":"OAuth 2.0 authorization server metadata (RFC 8414)","description":"Lucis.life auth docs as RFC 8414 metadata. Public clients use grant_type=client_credentials against POST /oauth/token. The catalog GET does not require a token.","security":[],"responses":{"200":{"description":"Authorization server metadata.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"getOAuthProtectedResourceMetadata","tags":["Discovery"],"summary":"OAuth 2.0 protected resource metadata (RFC 9728)","description":"RFC 9728 metadata for www.lucis.life. Lists authorization servers, bearer methods, and the catalog.read scope used by the optional client_credentials token.","security":[],"responses":{"200":{"description":"Protected resource metadata.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtectedResourceMetadata"}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"head":{"operationId":"headOAuthProtectedResourceMetadata","tags":["Discovery"],"summary":"OAuth 2.0 protected resource metadata (RFC 9728)","description":"RFC 9728 metadata for www.lucis.life. Lists authorization servers, bearer methods, and the catalog.read scope used by the optional client_credentials token.","security":[],"responses":{"200":{"description":"Protected resource metadata.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}}}}}},"/oauth/token":{"post":{"operationId":"issueOAuthToken","tags":["OAuth"],"summary":"Issue a client_credentials access token","description":"RFC 6749 token endpoint. Public clients may omit client authentication. The catalog GET does not require this token.","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/TokenRequest"}},"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}}},"responses":{"200":{"description":"Access token issued.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenSuccess"}}}},"400":{"description":"OAuth token error (RFC 6749 §5.2).","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthTokenError"}}}},"405":{"description":"Use POST on /oauth/token.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded. Honour Retry-After and RateLimit.","headers":{"RateLimit":{"description":"Live RFC RateLimit snapshot for the catalog policy, for example \"catalog\";r=59;t=60.","schema":{"type":"string","pattern":"^\"catalog\";r=\\d+;t=\\d+$"}},"RateLimit-Policy":{"description":"RFC RateLimit-Policy for the Lucis public catalog window. Quota is best-effort per compute instance. A shared store is not required for the public catalog.","schema":{"type":"string","const":"\"catalog\";q=60;w=60"}},"RateLimit-Limit":{"description":"Legacy window quota (requests).","schema":{"type":"integer","const":60}},"RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Legacy seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"type":"integer","minimum":1}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"Optional OAuth 2.0 client_credentials. Authorization-server metadata: https://www.lucis.life/.well-known/oauth-authorization-server","flows":{"clientCredentials":{"tokenUrl":"https://www.lucis.life/oauth/token","scopes":{"catalog.read":"Read the public biomarker catalog"}}}}},"schemas":{"Problem":{"type":"object","additionalProperties":false,"required":["type","title","status","detail","code"],"properties":{"type":{"type":"string","format":"uri","description":"RFC 9457 type URI identifying this problem class.","examples":["https://www.lucis.life/developers#not-found"]},"title":{"type":"string","description":"Short, human-readable summary of the problem type.","examples":["Not found"]},"status":{"type":"integer","description":"HTTP status code generated by the origin server.","examples":[404]},"detail":{"type":"string","description":"Human-readable explanation specific to this occurrence."},"code":{"type":"string","description":"Machine-readable Lucis error code.","enum":["bad_request","not_found","method_not_allowed","unsupported_grant_type","invalid_request","invalid_scope","bad_gateway","internal_error","rate_limited"]},"instance":{"type":"string","description":"Optional URI reference that identifies this occurrence."}}},"OAuthTokenError":{"type":"object","additionalProperties":false,"required":["error","error_description"],"properties":{"error":{"type":"string","description":"OAuth 2.0 error code from RFC 6749 §5.2.","enum":["invalid_request","unsupported_grant_type","invalid_scope","invalid_client"]},"error_description":{"type":"string","description":"Human-readable ASCII text providing additional information."}}},"BiomarkerCatalog":{"type":"object","additionalProperties":true,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/BiomarkerCatalogItem"}}}},"BiomarkerCatalogItem":{"type":"object","additionalProperties":true,"required":["uuid","translations"],"properties":{"id":{"type":"integer","description":"Internal numeric identifier when present."},"uuid":{"type":"string","format":"uuid","description":"Stable public biomarker identifier."},"unit":{"type":"string","description":"Display unit for the marker, when applicable."},"computedInternally":{"type":"boolean","description":"True when Lucis derives the marker rather than measuring it directly."},"premium":{"type":"boolean","description":"True when the marker is on a premium panel."},"metadata":{"type":"object","additionalProperties":true,"properties":{},"description":"Optional origin metadata on the public catalog item."},"category":{"type":"object","additionalProperties":true,"required":["uuid","translations"],"properties":{"uuid":{"type":"string","format":"uuid"},"type":{"type":"string","description":"Category key used in the Lucis catalog UI."},"imageUrl":{"type":"string","format":"uri"},"translations":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["name","locale"],"properties":{"name":{"type":"string","description":"Localized biomarker or category name."},"description":{"type":"string","description":"Optional localized presentation text."},"locale":{"type":"string","description":"BCP 47 locale, for example en or fr."}}}}}},"translations":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["name","locale"],"properties":{"name":{"type":"string","description":"Localized biomarker or category name."},"description":{"type":"string","description":"Optional localized presentation text."},"locale":{"type":"string","description":"BCP 47 locale, for example en or fr."}}}}}},"OpenApiDocument":{"type":"object","additionalProperties":false,"required":["openapi","info","paths"],"properties":{"openapi":{"type":"string","description":"OpenAPI version, currently 3.1.0."},"info":{"type":"object","additionalProperties":false,"required":["title","version"],"properties":{"title":{"type":"string"},"version":{"type":"string"},"summary":{"type":"string"},"description":{"type":"string"},"contact":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"url":{"type":"string","format":"uri"}}},"license":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"url":{"type":"string","format":"uri"}}}}},"jsonSchemaDialect":{"type":"string","format":"uri"},"servers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["url"],"properties":{"url":{"type":"string","format":"uri"},"description":{"type":"string"}}}},"tags":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}},"security":{"type":"array","items":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"paths":{"type":"object","additionalProperties":{"type":"object","description":"Path item object."}},"components":{"type":"object","additionalProperties":false,"properties":{"securitySchemes":{"type":"object"},"schemas":{"type":"object"},"headers":{"type":"object"}}},"externalDocs":{"type":"object","additionalProperties":false,"properties":{"description":{"type":"string"},"url":{"type":"string","format":"uri"}}}}},"TokenRequest":{"type":"object","additionalProperties":false,"required":["grant_type"],"properties":{"grant_type":{"type":"string","const":"client_credentials"},"scope":{"type":"string","default":"catalog.read"},"client_id":{"type":"string"}}},"TokenSuccess":{"type":"object","additionalProperties":false,"required":["access_token","token_type","expires_in","scope"],"properties":{"access_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","const":3600},"scope":{"type":"string","const":"catalog.read"}}},"AuthorizationServerMetadata":{"type":"object","additionalProperties":false,"required":["issuer","token_endpoint","response_types_supported"],"properties":{"issuer":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"scopes_supported":{"type":"array","items":{"type":"string"}},"response_types_supported":{"type":"array","items":{"type":"string"}},"grant_types_supported":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"}},"service_documentation":{"type":"string","format":"uri"},"ui_locales_supported":{"type":"array","items":{"type":"string"}}}},"ProtectedResourceMetadata":{"type":"object","additionalProperties":false,"required":["resource","authorization_servers"],"properties":{"resource":{"type":"string","format":"uri"},"authorization_servers":{"type":"array","items":{"type":"string","format":"uri"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"}},"resource_documentation":{"type":"string","format":"uri"},"scopes_supported":{"type":"array","items":{"type":"string"}}}}}},"externalDocs":{"description":"Lucis developer resources","url":"https://www.lucis.life/developers"}}