{"openapi":"3.1.0","info":{"title":"OKF Index","version":"1a422e37","description":"The search index of Open Knowledge Format bundles. Index: GET /api/."},"servers":[{"url":"https://www.okfindex.com"}],"components":{"schemas":{"Saude":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always `true` when the Worker answers."},"app":{"type":"string","description":"Display name of the product."},"build":{"type":"string","description":"Commit published (`dev` outside the CI)."}},"required":["ok","app","build"],"description":"Liveness of the Worker and the build it is serving."},"PaginaDeBundles":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Bundle"},"description":"The bundles on this page."},"limit":{"type":"integer","description":"Page size applied."},"offset":{"type":"integer","description":"Offset applied."},"next_offset":{"type":"integer","description":"Offset of the next page; `null` when there is no more (or past the 1000 cap).","nullable":true},"next":{"type":"string","description":"Absolute URL of the next page, same filters; follow it until it comes back `null`.","nullable":true}},"required":["items","limit","offset","next_offset","next"],"description":"A page of the index. No `total`: counting on every search would cost a scan without changing any decision — `GET /api/stats` has the totals."},"Bundle":{"type":"object","properties":{"id":{"type":"string","description":"Bundle id; the key across the whole API."},"name":{"type":"string","description":"Title of the root `index.md`, or `owner/repo · dir` when it has none."},"tagline":{"type":"string","description":"One line from the frontmatter `description`, or a generated summary."},"description":{"type":"string","description":"Body of the root `index.md`, capped at 1000 characters."},"okf_version":{"type":"string","description":"The `okf_version` the bundle declares (0.1 and 0.2 coexist)."},"concepts":{"type":"integer","description":"How many linked entries the root index lists."},"type":{"type":"string","description":"The `type` declared in the root frontmatter, when any."},"index_url":{"type":"string","description":"The root `index.md`, raw — what you hand to an agent."},"page_url":{"type":"string","description":"The page a human opens: the file on GitHub, or the bundle URL on its site."},"source":{"allOf":[{"$ref":"#/components/schemas/BundleSource"}],"description":"Provenance and location of the bundle."},"repo":{"allOf":[{"$ref":"#/components/schemas/RepoSignal"}],"description":"Repository signal; `null` for bundles served by a domain.","nullable":true},"indexed_at":{"type":"string","description":"When the bundle entered the index, `YYYY-MM-DD HH:MM:SS` UTC."},"updated_at":{"type":"string","description":"When its indexed content last changed, `YYYY-MM-DD HH:MM:SS` UTC."},"api":{"type":"string","description":"Absolute URL of this bundle's card."}},"required":["id","name","tagline","description","okf_version","concepts","type","index_url","page_url","source","repo","indexed_at","updated_at","api"],"description":"One OKF bundle: a markdown tree whose root `index.md` carries `okf_version`."},"BundleSource":{"type":"object","properties":{"origin":{"type":"string","description":"Provenance of the bundle."},"via":{"type":"string","description":"How it got in: the GitHub sweep or an IndexNow ping."},"url":{"type":"string","description":"The repository (GitHub) or the site root (domain)."},"host":{"type":"string","description":"Hostname of `url`; empty when it cannot be parsed."},"repo":{"type":"string","description":"`owner/repo` in lowercase, GitHub bundles only.","nullable":true},"dir":{"type":"string","description":"Directory of the bundle inside the repository (empty at the root)."},"path":{"type":"string","description":"Path of the root `index.md` inside the repository."}},"required":["origin","via","url","host","repo","dir","path"],"description":"Where a bundle comes from and how it entered the index."},"RepoSignal":{"type":"object","properties":{"stars":{"type":"integer","description":"Stargazers at the last collection."},"forks":{"type":"integer","description":"Forks at the last collection."},"pushed_at":{"type":"string","description":"Last push seen, `YYYY-MM-DD HH:MM:SS` UTC.","nullable":true},"state":{"type":"string","description":"Repository state as classified by the enricher (active, stalled, archived, gone).","nullable":true},"language":{"type":"string","description":"Primary language reported by GitHub.","nullable":true},"license":{"type":"string","description":"License identifier reported by GitHub.","nullable":true}},"required":["stars","forks","pushed_at","state","language","license"],"description":"Repository signal collected by the enricher — GitHub bundles only."},"IndexStats":{"type":"object","properties":{"total":{"type":"integer","description":"Live bundles in the index."},"by_origin":{"type":"object","description":"`{github, domain}`: live bundles found by the sweep and submitted by domains."},"last_update":{"type":"string","description":"Newest `updated_at` among live bundles, `YYYY-MM-DD HH:MM:SS` UTC.","nullable":true}},"required":["total","by_origin","last_update"],"description":"Size of the index by provenance, and when it last changed."}}},"paths":{"/agent.json":{"get":{"operationId":"get_agent_json","summary":"Agent card: identity, operator, documentation, the MCP endpoint and the tools it serves. Same document as `/.well-known/agent-card.json`.","description":"Returns: `application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` and `skills[]`.","responses":{"200":{"description":"`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` and `skills[]`."}}}},"/okf/{arquivo}":{"get":{"operationId":"get_okf_by_arquivo","summary":"OKF bundle (Open Knowledge Format v0.1): markdown with frontmatter so an agent reads the whole product without parsing HTML.","description":"Returns: `text/markdown`. Start at `/okf/index.md`, which lists the bundle.","parameters":[{"name":"arquivo","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"`text/markdown`. Start at `/okf/index.md`, which lists the bundle."},"404":{"description":"File outside the bundle."}}}},"/.well-known/{arquivo}":{"get":{"operationId":"get_well_known_by_arquivo","summary":"Machine discovery before the home page: `api-catalog` (RFC 9727, a linkset with the API and the MCP), `security.txt` (RFC 9116), `x402` (payment manifest: network, wallet and the routes that charge) and `mcp-registry-auth` (the official MCP registry key).","description":"Returns: `application/linkset+json` for the api-catalog; `application/json` for x402 and apis.json; `text/plain` for the other two.","parameters":[{"name":"arquivo","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"`application/linkset+json` for the api-catalog; `application/json` for x402 and apis.json; `text/plain` for the other two."},"404":{"description":"Name outside the five published."}}}},"/apis.json":{"get":{"operationId":"get_apis_json","summary":"APIs.json (apisjson.org, 0.19): the index APIs.io harvests — the API, the MCP, OpenAPI, guide and OKF bundle in one file. Also at `/.well-known/apis.json`.","description":"Returns: `application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`.","responses":{"200":{"description":"`application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`."}}}},"/api/":{"get":{"operationId":"api_index","summary":"Índice auto-descrito: cada rota, o que cobra e como plugar o MCP.","description":"Returns: { name, description, build, base_url, docs, endpoints, mcp_tools }","responses":{"200":{"description":"{ name, description, build, base_url, docs, endpoints, mcp_tools }","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Nome do produto."},"description":{"type":"string","description":"O que o produto faz."},"build":{"type":"string","description":"Commit publicado."},"base_url":{"type":"string","description":"Origem em que esta API está servindo."},"docs":{"type":"object","description":"Links para llms.txt, OpenAPI, MCP e a UI."},"endpoints":{"type":"array","items":{"type":"object"},"description":"Catálogo de endpoints."},"mcp_tools":{"type":"array","items":{"type":"string"},"description":"Tools do MCP."}},"required":["name","description","build","base_url","docs","endpoints","mcp_tools"]}}}}}}},"/api/health":{"get":{"operationId":"get_api_health","summary":"Liveness and the build being served.","description":"Returns: { ok, app, build }","responses":{"200":{"description":"{ ok, app, build }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Saude"}}}}}}},"/mcp":{"post":{"operationId":"post_mcp","summary":"MCP Streamable HTTP — as tools deste catálogo, despachadas neste mesmo Worker.","description":"Returns: JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`).","responses":{"200":{"description":"JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`)."}}}},"/api/bundles":{"get":{"operationId":"search_bundles","summary":"Paginated search of the index: every live OKF bundle, from GitHub and from live domains.","description":"Only `live` bundles. Free text matches the name, the tagline, the description and the origin identifier (`owner/repo:path` or the bundle URL). No `total` on purpose: `GET /api/stats` has it.\nReturns: { items[{id,name,tagline,description,okf_version,concepts,type,index_url,page_url,source,repo,indexed_at,updated_at,api}], limit, offset, next_offset, next }","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Free text over name, tagline, description and origin identifier.","example":"agent"},{"name":"origin","in":"query","required":false,"schema":{"type":"string","enum":["github","domain"]},"description":"Provenance: found by the GitHub sweep, or submitted by a domain."},{"name":"repo","in":"query","required":false,"schema":{"type":"string"},"description":"Only bundles of one repository, `owner/repo` (case-insensitive).","example":"fastendpoints/fastendpoints"},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"recent","enum":["recent","updated","name","stars"]},"description":"Result order: arrival, last content change, name or repository stars."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":24},"description":"Bundles per page, at most 100."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"How many bundles to skip. Use `next_offset` from the previous response; the list ends at 1000."}],"responses":{"200":{"description":"{ items[{id,name,tagline,description,okf_version,concepts,type,index_url,page_url,source,repo,indexed_at,updated_at,api}], limit, offset, next_offset, next }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginaDeBundles"}}}}}}},"/api/bundles/{id}":{"get":{"operationId":"get_bundle","summary":"One bundle's card, by id.","description":"`live` and `low` (example or fixture bundles kept out of the search) both answer here.\nReturns: { id, name, tagline, description, okf_version, concepts, type, index_url, page_url, source{origin,via,url,host,repo,dir,path}, repo{stars,forks,pushed_at,state,language,license}, indexed_at, updated_at, api }","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ id, name, tagline, description, okf_version, concepts, type, index_url, page_url, source{origin,via,url,host,repo,dir,path}, repo{stars,forks,pushed_at,state,language,license}, indexed_at, updated_at, api }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bundle"}}}},"404":{"description":"No bundle with that id, or it is not public."}}}},"/api/stats":{"get":{"operationId":"index_stats","summary":"Size of the index by provenance, and when it last changed.","description":"Returns: { total, by_origin, last_update }","responses":{"200":{"description":"{ total, by_origin, last_update }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexStats"}}}}}}},"/api/ping":{"post":{"operationId":"submit_bundles","summary":"Submits OKF bundles from a domain you control, using the IndexNow protocol.","description":"No account, no payment: ownership is proved by a key file on the host, exactly as IndexNow does it. Host `https://<host>/<key>.txt` containing the key (or point `keyLocation` at another path on the SAME host), then send the bundle URLs. We answer **202**: the key has not been checked yet. Verification and reading happen on our collector, never at the edge — so nothing is published, and no URL of yours is fetched, before the key matches. Re-sending a URL is how you say the bundle changed; it goes back in line to be re-read. At most 100 URLs per request and 200 per host per UTC day. Bundles in public GitHub repositories need no ping: the sweep finds them.\nReturns: { ok, estado, host, recebidos, chave_em, mensagem, api_index }","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"urlList":{"type":"array","items":{"type":"string"},"description":"The bundle roots (`index.md` files): https, on `host`, ending in .md — any path, since the spec fixes none."},"host":{"type":"string","description":"The domain that serves the bundles and the key file."},"key":{"type":"string","description":"The IndexNow key: 8 to 128 characters of [a-zA-Z0-9-]."},"keyLocation":{"type":"string","description":"Alternative location of the key file, on the SAME host. Default: `https://<host>/<key>.txt`."}},"required":["urlList","host","key"]},"example":{"urlList":["https://kb.example.org/knowledge/index.md"],"host":"kb.example.org","key":"okf-2026-09-08-k3y"}}}},"responses":{"202":{"description":"{ ok, estado, host, recebidos, chave_em, mensagem, api_index }","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"The submission was queued."},"estado":{"type":"string","description":"Always `pendente`: the key has not been checked yet."},"host":{"type":"string","description":"The host as normalized (lowercase)."},"recebidos":{"type":"integer","description":"How many distinct URLs entered the queue."},"chave_em":{"type":"string","description":"Where we will look for the key file. Check it if you are unsure."},"mensagem":{"type":"string","description":"What happens next, in one sentence."},"api_index":{"type":"string","description":"Absolute URL of this API's index."}},"required":["ok","estado","host","recebidos","chave_em","mensagem","api_index"]}}}},"400":{"description":"Body is not JSON, `host` is not a domain, `key` is out of shape, or `urlList` is missing/empty/over 100."},"422":{"description":"Some URL is not https, does not end in .md or lives on another host; `keyLocation` off-host too."},"429":{"description":"The host already submitted 200 bundles this UTC day."}}}},"/api/visit":{"post":{"operationId":"post_api_visit","summary":"One ping per page view from the interface; it feeds the index's own visit counter.","description":"Counted under the index's metric (`okf_visit`), apart from the Meta Agent Tools counter that shares the database. Test traffic is left out: `X-MM-Smoke`, User-Agent `mm-smoke` or `smoke: true`.\nReturns: { counted, ok }","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"smoke":{"type":"boolean","description":"`true` flags a test call, which is acknowledged but not counted."},"p":{"type":"string","description":"Path of the page that was opened (informative)."}}},"example":{"p":"/","smoke":false}}}},"responses":{"200":{"description":"{ counted, ok }","content":{"application/json":{"schema":{"type":"object","properties":{"counted":{"type":"boolean","description":"`false` for test traffic, `true` when the day's counter moved."},"ok":{"type":"boolean","description":"Always `true`; the route never refuses a ping."}},"required":["counted","ok"]}}}}}}},"/api/metrics":{"get":{"operationId":"get_api_metrics","summary":"Usage of the index for the house dashboard: bundles indexed, visits and MCP calls per day.","description":"Anonymous calls get the usage block only. Send `METRICS_TOKEN` as Bearer and the finance block is added — all zeros, because nothing here is charged.\nReturns: `{app, today, today_visits, days[], usage: {okf, mcp}, accounts, payments?}`.","parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"},"description":"Optional `Bearer <METRICS_TOKEN>`; unlocks the zeroed finance block."}],"responses":{"200":{"description":"`{app, today, today_visits, days[], usage: {okf, mcp}, accounts, payments?}`."},"401":{"description":"Token present but wrong."},"503":{"description":"Token present, but the Worker has no `METRICS_TOKEN` to compare."}}}},"/api/erro-cliente":{"post":{"operationId":"post_api_erro_cliente","summary":"Browser error report, sent by the interface itself. Agents need not call it.","description":"The interface reports on its own JS errors, unhandled rejections, scripts/CSS that failed to load and CSP blocks — once per session — and the app reports handled failures through `window.mmErro.relata`. The server validates the envelope, redacts credentials, e-mails and phone numbers, merges repeats of the same failure per minute and records an operational event; nothing is written to a database. It keeps no IP, cookie, query string or full User-Agent. Always answers 204, even for an invalid report.\nReturns: 204 with no body, always — an invalid, repeated or over-cap report also gets 204.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","description":"Failure code, `UI-` + letters/digits (`UI-JS-001` global error, `UI-PROMESSA-001`, `UI-RECURSO-001`, `UI-CSP-001`, `UI-APP-001` app report)."},"phase":{"type":"string","description":"Where it broke, lowercase: `global`, `promessa`, `script`, `load_list`…"},"path":{"type":"string","description":"Path of the open page, without query."},"message":{"type":"string","description":"Error message, up to 2000 characters."},"stack":{"type":"string","description":"Stack trace, up to 12000 characters."},"source":{"type":"string","description":"Originating script; only its path is kept."},"line":{"type":"integer","description":"Line in the originating script."},"column":{"type":"integer","description":"Column in the originating script."},"visivel":{"type":"boolean","description":"Whether the tab was visible when it broke."}},"required":["code","phase"]},"example":{"code":"UI-APP-001","phase":"carregar_lista","path":"/","message":"lista 500"}}}},"responses":{"200":{"description":"204 with no body, always — an invalid, repeated or over-cap report also gets 204."}}}}}}