{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Klarum product catalogue","schema_version":2,"catalog_version":"2026.08.26","endpoints":{"GET /api/catalog":{"$ref":"#/$defs/CatalogCardIndexResponse"},"GET /api/catalog/modules/{id}":{"$ref":"#/$defs/CatalogCardModuleResponse"}},"$defs":{"CatalogCardBody":{"description":"The two prose fields that describe the PRODUCT rather than the build.","properties":{"what_it_is":{"title":"What It Is","type":"string"},"what_it_helps_users_do":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"What It Helps Users Do"}},"required":["what_it_is"],"title":"CatalogCardBody","type":"object"},"CatalogCardCapability":{"description":"A capability as an anonymous caller sees it.","properties":{"id":{"title":"Id","type":"string"},"type":{"$ref":"#/$defs/NodeType","default":"capability"},"title":{"title":"Title","type":"string"},"summary":{"title":"Summary","type":"string"},"status":{"$ref":"#/$defs/Status","default":"ga"},"scope":{"anyOf":[{"$ref":"#/$defs/Scope"},{"type":"null"}],"default":null},"keywords":{"items":{"type":"string"},"title":"Keywords","type":"array"},"body":{"anyOf":[{"$ref":"#/$defs/CatalogCardBody"},{"type":"null"}],"default":null}},"required":["id","title","summary"],"title":"CatalogCardCapability","type":"object"},"CatalogCardChip":{"description":"A capability as a chip on a module card: name, one line, shipping state.","properties":{"id":{"title":"Id","type":"string"},"title":{"title":"Title","type":"string"},"summary":{"title":"Summary","type":"string"},"status":{"$ref":"#/$defs/Status","default":"ga"}},"required":["id","title","summary"],"title":"CatalogCardChip","type":"object"},"CatalogCardCounts":{"description":"Sizes an anonymous caller may know.\n\nNo ``surfaces`` and no ``relations``. The relation total was rendered as\n\"Relations 86\" on the public page, which advertises the size of the wiring\ngraph to someone who is not allowed to see the wiring graph.","properties":{"modules":{"title":"Modules","type":"integer"},"capabilities":{"title":"Capabilities","type":"integer"},"engines":{"title":"Engines","type":"integer"},"integrations":{"title":"Integrations","type":"integer"}},"required":["modules","capabilities","engines","integrations"],"title":"CatalogCardCounts","type":"object"},"CatalogCardIndexResponse":{"description":"``GET /api/catalog``: the anonymous table of contents.","properties":{"schema_version":{"title":"Schema Version","type":"integer"},"catalog_version":{"description":"Version stamp of the authored catalogue, YYYY.MM.DD.","title":"Catalog Version","type":"string"},"generated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Generated At"},"counts":{"$ref":"#/$defs/CatalogCardCounts"},"modules":{"items":{"$ref":"#/$defs/CatalogCardSummary"},"title":"Modules","type":"array"},"preambles":{"additionalProperties":{"type":"string"},"title":"Preambles","type":"object"}},"required":["schema_version","catalog_version","counts"],"title":"CatalogCardIndexResponse","type":"object"},"CatalogCardModuleResponse":{"description":"``GET /api/catalog/modules/{id}``: one module, anonymously.","properties":{"id":{"title":"Id","type":"string"},"type":{"$ref":"#/$defs/NodeType","default":"module"},"title":{"title":"Title","type":"string"},"status":{"$ref":"#/$defs/Status"},"audience":{"items":{"type":"string"},"title":"Audience","type":"array"},"scope":{"$ref":"#/$defs/Scope"},"tier_min":{"description":"Lowest subscription tier that includes the module.","title":"Tier Min","type":"string"},"aliases":{"items":{"type":"string"},"title":"Aliases","type":"array"},"summary":{"title":"Summary","type":"string"},"keywords":{"items":{"type":"string"},"title":"Keywords","type":"array"},"body":{"$ref":"#/$defs/CatalogCardBody"},"engines":{"items":{"$ref":"#/$defs/CatalogCardNamed"},"title":"Engines","type":"array"},"integrations":{"items":{"$ref":"#/$defs/CatalogCardNamed"},"title":"Integrations","type":"array"},"capabilities":{"items":{"$ref":"#/$defs/CatalogCardCapability"},"title":"Capabilities","type":"array"}},"required":["id","title","status","scope","tier_min","summary","body"],"title":"CatalogCardModuleResponse","type":"object"},"CatalogCardNamed":{"description":"An engine or integration as an anonymous caller sees it: name and purpose.\n\nThat a rerank service exists is a product fact. Which host it runs on, and on\nwhich port, is not - and that is the difference between this and\n``CatalogEngine``.","properties":{"id":{"title":"Id","type":"string"},"type":{"$ref":"#/$defs/NodeType"},"title":{"title":"Title","type":"string"},"summary":{"title":"Summary","type":"string"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Category"}},"required":["id","type","title","summary"],"title":"CatalogCardNamed","type":"object"},"CatalogCardSummary":{"description":"A module in the anonymous index. No ``surfaces``: those are route paths.\n\n``capabilities`` are inlined rather than left to ``/modules/{id}``, which is a\ndeliberate departure from the authenticated index. The public page is a card\ngrid - a card without its capabilities does not say what the module actually\ndoes - and the alternative is eighteen round trips on the first paint of an\nanonymous page. They are chips (title, one line, status), not full capability\nobjects, so the index stays an index.","properties":{"id":{"title":"Id","type":"string"},"ordinal":{"description":"1-based position in catalogue declaration order.","title":"Ordinal","type":"integer"},"title":{"title":"Title","type":"string"},"summary":{"title":"Summary","type":"string"},"status":{"$ref":"#/$defs/Status"},"scope":{"$ref":"#/$defs/Scope"},"tier_min":{"description":"Lowest subscription tier that includes the module.","title":"Tier Min","type":"string"},"audience":{"items":{"type":"string"},"title":"Audience","type":"array"},"keywords":{"items":{"type":"string"},"title":"Keywords","type":"array"},"capabilities":{"items":{"$ref":"#/$defs/CatalogCardChip"},"title":"Capabilities","type":"array"}},"required":["id","ordinal","title","summary","status","scope","tier_min"],"title":"CatalogCardSummary","type":"object"},"NodeType":{"description":"What a node in the catalogue graph is.","enum":["module","capability","surface","engine","integration"],"title":"NodeType","type":"string"},"Scope":{"description":"Which side of the two-sided platform a node belongs to.","enum":["supplier","issuer","both"],"title":"Scope","type":"string"},"Status":{"description":"Shipping state, as published to anyone who can read the catalogue.\n\nWHY THERE IS NO ``broken`` OR ``partial`` HERE (KL-657, reversed on review)\n\nA first pass added them, because the audit was right that 113 of 116 nodes\nbeing ``ga`` made the chip carry no information. It was the wrong fix for a\nCUSTOMER-FACING surface: this artifact is served at app.klarum.com/catalog\nand read by the marketing repo, and a procurement team evaluating us must\nnever read an amber PARTIAL or a red BROKEN on the product page. A bug\nreport is not a product claim.\n\nThe rule that replaces it, and it is the same information stated\npositively: ``ga`` means it works AND a user can reach it. Anything a user\ncannot reach yet is ``planned``, whatever fraction of it is built. That is\nwhat stopped everything being ``ga`` - two capabilities moved to\n``planned`` rather than being labelled defective in public.\n\nHonest internal grading (``works | partial | broken``) lives in ``sor/``,\nwhich is internal by construction and never published.","enum":["ga","beta","flagged","planned","retired"],"title":"Status","type":"string"}}}