{
  "name": "Meta Agent Tools",
  "description": "Find MCP servers, Agent Skills and plugins, with project details, activity signals and community feedback. Submissions are reviewed before publication. This is an independent catalog.",
  "auth": {
    "credito": "Prepaid credit token in `Authorization: Bearer cred_…` (or the `X-Credito` header). Not an account: it is a bearer of balance.",
    "none": "Public, no credential.",
    "guest": "Guest token (`POST /api/guest`) in `X-Guest-Token: mr_…` or `Authorization: Bearer mr_…`. In the browser it also lives in the HttpOnly `guest` cookie, which writes only from this site's exact Origin. A signed-in account (cookie) also works and takes precedence.",
    "session": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans.",
    "session_ou_x402": "Two doors to the SAME action: a human with the account session (cookie; free, within the quota) or an agent paying x402 (`X-PAYMENT`). A guest token is neither required nor blocks the paid path.",
    "token": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
  },
  "docs": {
    "llms": "https://staging.agentalog.com/llms.txt",
    "llms_full": "https://staging.agentalog.com/llms-full.txt",
    "openapi": "https://staging.agentalog.com/openapi.json",
    "mcp": "https://staging.agentalog.com/mcp",
    "pricing": "https://staging.agentalog.com/api/pricing",
    "billing": "https://staging.agentalog.com/api/billing",
    "human_ui": "https://staging.agentalog.com/",
    "data_indexes": [
      {
        "id": "cep",
        "produto": "https://pontofato.com",
        "caminho": "/enderecos",
        "title": "Postal codes and addresses",
        "description": "Find addresses by location, with coordinates and a 2022 reference date. Not a current postal-code certification.",
        "hierarchy": "State → municipality → locality → street → addresses",
        "url": "https://api.pontofato.com/enderecos/",
        "formats": {
          "html": "https://api.pontofato.com/enderecos/",
          "json": "https://api.pontofato.com/enderecos/index.json",
          "md": "https://api.pontofato.com/enderecos/index.md",
          "okf": "https://api.pontofato.com/enderecos/index.okf.md"
        },
        "llms": "https://api.pontofato.com/enderecos/llms.txt",
        "openapi": "https://api.pontofato.com/enderecos/openapi.json",
        "mcp": "https://api.pontofato.com/enderecos/mcp",
        "okf": "https://api.pontofato.com/enderecos/okf/index.md",
        "access": "public-read-only",
        "pagination": {
          "max_items": 20,
          "next": "links.proximo"
        },
        "updates": "manual"
      },
      {
        "id": "editais",
        "produto": "https://editalmd.com",
        "caminho": "/licitacoes",
        "title": "Public procurement",
        "description": "Find public procurement by location and date. View documents and reading options in EditalMD.",
        "hierarchy": "Procedure → state → year → month → day → municipality → purchases",
        "url": "https://api.editalmd.com/licitacoes/",
        "formats": {
          "html": "https://api.editalmd.com/licitacoes/",
          "json": "https://api.editalmd.com/licitacoes/index.json",
          "md": "https://api.editalmd.com/licitacoes/index.md",
          "okf": "https://api.editalmd.com/licitacoes/index.okf.md"
        },
        "llms": "https://api.editalmd.com/licitacoes/llms.txt",
        "openapi": "https://api.editalmd.com/licitacoes/openapi.json",
        "mcp": "https://api.editalmd.com/licitacoes/mcp",
        "okf": "https://api.editalmd.com/licitacoes/okf/index.md",
        "access": "public-read-only",
        "pagination": {
          "max_items": 20,
          "next": "links.proximo"
        },
        "updates": "manual"
      }
    ]
  },
  "endpoints": [
    {
      "method": "GET",
      "path": "/agent.json",
      "auth": "none",
      "summary": "Agent card: identity, operator, documentation, the MCP endpoint and the tools it serves. Same document as `/.well-known/agent-card.json`.",
      "grupo": "Discovery",
      "retorno": {
        "_texto": "`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` and `skills[]`."
      },
      "exemplo": "curl -s $ORIGIN/agent.json",
      "returns": "`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` and `skills[]`.",
      "url": "https://staging.agentalog.com/agent.json",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/okf/:arquivo",
      "auth": "none",
      "summary": "OKF bundle (Open Knowledge Format v0.1): markdown with frontmatter so an agent reads the whole product without parsing HTML.",
      "grupo": "Discovery",
      "params": {
        "arquivo": {
          "desc": "`index.md`, `sobre.md`, `api.md` or `faq.md`.",
          "exemplo": "index.md"
        }
      },
      "retorno": {
        "_texto": "`text/markdown`. Start at `/okf/index.md`, which lists the bundle."
      },
      "erros": {
        "404": "File outside the bundle."
      },
      "exemplo": "curl -s $ORIGIN/okf/index.md",
      "returns": "`text/markdown`. Start at `/okf/index.md`, which lists the bundle.",
      "url": "https://staging.agentalog.com/okf/:arquivo",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/.well-known/:arquivo",
      "auth": "none",
      "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).",
      "grupo": "Discovery",
      "params": {
        "arquivo": {
          "desc": "`api-catalog`, `security.txt`, `x402`, `mcp-registry-auth` or `apis.json`.",
          "exemplo": "api-catalog"
        }
      },
      "retorno": {
        "_texto": "`application/linkset+json` for the api-catalog; `application/json` for x402 and apis.json; `text/plain` for the other two."
      },
      "erros": {
        "404": "Name outside the five published."
      },
      "exemplo": "curl -s $ORIGIN/.well-known/api-catalog",
      "returns": "`application/linkset+json` for the api-catalog; `application/json` for x402 and apis.json; `text/plain` for the other two.",
      "url": "https://staging.agentalog.com/.well-known/:arquivo",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/apis.json",
      "auth": "none",
      "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`.",
      "grupo": "Discovery",
      "retorno": {
        "_texto": "`application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`."
      },
      "exemplo": "curl -s $ORIGIN/apis.json",
      "returns": "`application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`.",
      "url": "https://staging.agentalog.com/apis.json",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/feed.xml",
      "auth": "none",
      "summary": "RSS 2.0 of the most recently published listings.",
      "grupo": "Discovery",
      "retorno": {
        "_texto": "`application/rss+xml`."
      },
      "exemplo": "curl -s $ORIGIN/feed.xml",
      "returns": "`application/rss+xml`.",
      "url": "https://staging.agentalog.com/feed.xml",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/feed.json",
      "auth": "none",
      "summary": "JSON Feed 1.1 of the most recently published listings — the same stream as the RSS.",
      "grupo": "Discovery",
      "retorno": {
        "_texto": "`application/feed+json`."
      },
      "exemplo": "curl -s $ORIGIN/feed.json",
      "returns": "`application/feed+json`.",
      "url": "https://staging.agentalog.com/feed.json",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/",
      "auth": "none",
      "summary": "Self-describing index: the whole API surface, with quota and quickstart.",
      "grupo": "Discovery",
      "retorno": {
        "name": {
          "tipo": "string",
          "desc": "Product name."
        },
        "description": {
          "tipo": "string",
          "desc": "What the registry is and what it is not."
        },
        "auth": {
          "tipo": "object",
          "desc": "Each authentication mode and how to obtain it."
        },
        "docs": {
          "tipo": "object",
          "desc": "Links to llms.txt, llms-full.txt, openapi.json, MCP and the UI."
        },
        "endpoints": {
          "tipo": "object[]",
          "desc": "Every endpoint with method, path, auth, absolute URL and what it returns."
        },
        "quota": {
          "tipo": "object",
          "desc": "What is free, what costs and how to pay — before you spend a call."
        },
        "mcp": {
          "tipo": "object",
          "desc": "Address and transport of the MCP server."
        },
        "quickstart": {
          "tipo": "string[]",
          "desc": "The calls that take you from zero to the first published listing."
        }
      },
      "returns": "{ name, description, auth, docs, endpoints, quota, mcp, quickstart }",
      "url": "https://staging.agentalog.com/api/",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/health",
      "auth": "none",
      "summary": "Liveness and the commit deployed right now — it is how the smoke waits for its own deploy.",
      "grupo": "Discovery",
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true` when the Worker answers."
        },
        "app": {
          "tipo": "string",
          "desc": "Product name."
        },
        "build": {
          "tipo": "string",
          "desc": "Deployed commit; CI passes the short SHA on deploy."
        },
        "ts": {
          "tipo": "string",
          "desc": "Time of the response (UTC, ISO-8601)."
        }
      },
      "returns": "{ ok, app, build, ts }",
      "url": "https://staging.agentalog.com/api/health",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/mcp",
      "auth": "none",
      "summary": "MCP server over HTTP (Streamable HTTP, JSON-RPC 2.0) — plugs into the client with nothing to install.",
      "grupo": "Discovery",
      "desc": "The tools are the operations of this same catalog; the MCP has no backend of its own. `GET /mcp` returns the server card.",
      "retorno": {
        "_texto": "JSON-RPC 2.0 response (`initialize`, `tools/list` or `tools/call`)."
      },
      "notes": [
        "Credentials go in the usual headers (X-Guest-Token, Authorization, X-PAYMENT) and are forwarded to the API.",
        "An exhausted quota comes back as a 402 with accepts[] inside the tool result — pay and repeat."
      ],
      "exemplo": "curl -s -XPOST $ORIGIN/mcp -H 'content-type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}'",
      "returns": "JSON-RPC 2.0 response (`initialize`, `tools/list` or `tools/call`).",
      "url": "https://staging.agentalog.com/mcp",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/guest",
      "auth": "none",
      "summary": "Creates a guest `mr_…` — it is the identity that likes, comments and visits.",
      "grupo": "Identity",
      "desc": "Asks for no e-mail. Publishing a listing is what requires an account (or a payment). At most 20 new guests per network per hour; a browser that already has one gets it back from the `guest` cookie.",
      "retorno": {
        "token": {
          "tipo": "string",
          "desc": "The guest, prefix `mr_`. Send it in `X-Guest-Token` or as Bearer."
        }
      },
      "erros": {
        "429": "More than 20 new guests from the same network in the hour.",
        "503": "auth_unavailable"
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/guest",
      "returns": "{ token }",
      "url": "https://staging.agentalog.com/api/guest",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/listings",
      "auth": "none",
      "colecao": {
        "porPagina": 50,
        "anda": "next"
      },
      "summary": "The public mosaic: paginated search of the catalog's listings, the lower-signal tail last.",
      "grupo": "Catalog",
      "desc": "`live` listings first and the `low` tail (few stars or no clear license) after them in every order — `low=0` leaves the tail out. To walk everything, follow `next`: without `q` it is a cursor (`next_cursor`, keyset on the order's index) and has no ceiling; every listing also has an HTML page at `/l/:id` and the shards of `/sitemap-listings.xml` list them all. `q` runs on a full-text index (FTS5, bm25) kept in the same transaction as every text write. With `q` and `low=0`, `low_count` says how many `low` listings the filter left out — LIKE with a cap of 200. The query is mapped onto kind/topic/transport filters unless `interpret=0`.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Free text over the name, the tagline, the description, the origin identifier and the README excerpt: every word (up to six, 2+ letters, accents ignored) must match; ranked by bm25 with the name weighing most (10), then tagline (5), identifier (3), description (2), README excerpt (1); ties by stars. Kind, topic and transport words become filters. The `low` tail is in the same index.",
          "exemplo": "browser testing"
        },
        "interpret": {
          "tipo": "string",
          "desc": "`0` disables query understanding and searches the raw string.",
          "valores": [
            "0"
          ]
        },
        "kind": {
          "tipo": "string",
          "desc": "Which kind of resource to fetch.",
          "valores": [
            "mcp",
            "skill",
            "plugin"
          ]
        },
        "category": {
          "tipo": "string",
          "desc": "Category declared by whoever published."
        },
        "sort": {
          "tipo": "string",
          "desc": "Result order. Without it, a query is ranked by relevance — bm25 over the full-text index (name 10, tagline 5, identifier 3, description 2, README excerpt 1) multiplied by 1 + 0.05·ln(1 + stars) + 0.1 if pushed in the last 180 days + 0.1 if a README was collected; ties by stars — and a plain listing by arrival.",
          "valores": [
            "relevancia",
            "recent",
            "stars",
            "likes",
            "visits",
            "nome"
          ],
          "padrao": "relevancia when q is set, recent otherwise"
        },
        "low": {
          "tipo": "string",
          "desc": "`0` leaves the `low` tail out; by default it comes after the `live` listings in every order.",
          "valores": [
            "0"
          ]
        },
        "cursor": {
          "tipo": "string",
          "desc": "Opaque cursor from `next_cursor` of the previous page (orders `recent`, `stars` and `nome`, without `q`). With it, `offset` is ignored. A cursor from another order or a malformed one restarts at the first page."
        },
        "limit": {
          "tipo": "int",
          "desc": "Listings per page.",
          "padrao": 24
        },
        "offset": {
          "tipo": "int",
          "desc": "How many listings to skip. No ceiling since 2026-09-13, but the database reads every skipped row: to walk the catalog, follow `next` (cursor) instead.",
          "padrao": 0
        }
      },
      "retorno": "PaginaDeAnuncios",
      "exemplo": "curl -s '$ORIGIN/api/listings?kind=mcp&sort=likes&limit=5'",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "returns": "{ items[{id,kind,category,name,tagline,body,url,status,origin,origin_id,install,source,transporte,ns,versao,oficial_status,repo_host,topico,linguagem,licenca,repo_topics,repo_slug,stars,forks,prs_abertos,pushed_at,repo_estado,likes,comments,visits,created_at,updated_at,mine,api,go,comments_api,readme_api?,historico?,readme_fonte?,readme_bytes,readme_sha,readme_em,payload}], limit, offset, next_offset, next_cursor, next, low_count, low_capped, low_included, interpretacao, api }",
      "url": "https://staging.agentalog.com/api/listings",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/facets",
      "auth": "none",
      "summary": "The whole catalog's counts by kind, provenance, category and repository state.",
      "grupo": "Catalog",
      "desc": "Exists to build a filter without sweeping the listings: there are tens of thousands, and asking for the list just to count would be expensive. Also brings `topico_inferido`, deduced from the repositories.",
      "retorno": "Facetas",
      "exemplo": "curl -s $ORIGIN/api/facets",
      "returns": "{ total, facetas, topico_inferido, interpretacao, publicador?, api }",
      "url": "https://staging.agentalog.com/api/facets",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/v0.1/servers",
      "auth": "none",
      "summary": "MCP subregistry in the Official Registry format (spec v0.1), cursor-paginated.",
      "grupo": "Catalog",
      "desc": "Only `kind=mcp` and only `live`. It is the route a generic MCP client knows how to read without knowing this product. `GET /v0/servers` is an alias of the same resource, kept for whoever already pointed there — this is the canonical URL.",
      "query": {
        "search": {
          "tipo": "string",
          "desc": "Free text over the server's name and description."
        },
        "cursor": {
          "tipo": "string",
          "desc": "Opaque cursor of the next page, from `metadata.next_cursor`."
        },
        "limit": {
          "tipo": "int",
          "desc": "Servers per page.",
          "padrao": 30
        }
      },
      "retorno": "PaginaV01",
      "exemplo": "curl -s '$ORIGIN/v0.1/servers?search=postgres&limit=5'",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "returns": "{ servers[{name,description,version,repository,remotes,packages}], metadata }",
      "url": "https://staging.agentalog.com/v0.1/servers",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/listings/:id",
      "auth": "none",
      "summary": "One listing's page. The owner sees their own even when pending or hidden.",
      "grupo": "Catalog",
      "params": {
        "id": {
          "desc": "Listing ID, from `Anuncio.id`."
        }
      },
      "retorno": "Anuncio",
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "404": "The listing does not exist, or it is not yours and is not live/low.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s $ORIGIN/api/listings/ID",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ id, kind, category, name, tagline, body, url, status, origin, origin_id, install, source, transporte, ns, versao, oficial_status, repo_host, topico, linguagem, licenca, repo_topics, repo_slug, stars, forks, prs_abertos, pushed_at, repo_estado, likes, comments, visits, created_at, updated_at, mine, api, go, comments_api, readme_api?, historico?, readme_fonte?, readme_bytes, readme_sha, readme_em, payload }",
      "url": "https://staging.agentalog.com/api/listings/:id",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/listings/:id/readme",
      "auth": "none",
      "summary": "README collected from the listing's repository, served on open.",
      "grupo": "Catalog",
      "desc": "The text lives in R2 (`mural-coleta`). This call does not write and does not fetch GitHub. Same visibility as the listing page. Call it only when the listing page carries `readme_api`: a page without it has no README collected, and this route answers 404.",
      "params": {
        "id": {
          "desc": "Listing ID, from `Anuncio.id`."
        }
      },
      "retorno": "Readme",
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "404": "The listing does not exist, is not visible, or no README was collected.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s $ORIGIN/api/listings/ID/readme",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ markdown, bytes, sha, repo_slug, fonte, truncated, api }",
      "url": "https://staging.agentalog.com/api/listings/:id/readme",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/go/:id",
      "auth": "none",
      "summary": "Hop to the listing's URL: redirects and counts the visit.",
      "grupo": "Catalog",
      "desc": "Counts at most 1 visit per owner per day. The `X-Visit-Counted` header says whether this call counted — it is how the client knows without counting twice.",
      "params": {
        "id": {
          "desc": "ID of the listing to visit.",
          "exemplo": "lst_9f3c2b1d7a4e58b0c2d4"
        }
      },
      "retorno": {
        "_texto": "`302` with `Location` to the listing's URL, and the `X-Visit-Counted` header."
      },
      "erros": {
        "404": "The listing does not exist or is not live/low."
      },
      "returns": "`302` with `Location` to the listing's URL, and the `X-Visit-Counted` header.",
      "url": "https://staging.agentalog.com/api/go/:id",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/listings/:id/comments",
      "auth": "none",
      "summary": "Public comments on a live listing.",
      "grupo": "Community",
      "desc": "With a credential on the call, each comment of yours comes with `mine: true`.",
      "params": {
        "id": {
          "desc": "ID of the listing."
        }
      },
      "retorno": {
        "items": {
          "tipo": "Comentario[]",
          "desc": "The comments, newest first."
        },
        "total": {
          "tipo": "int",
          "desc": "How many comments the listing has."
        }
      },
      "erros": {
        "404": "The listing does not exist or is not live."
      },
      "exemplo": "curl -s $ORIGIN/api/listings/ID/comments",
      "returns": "{ items[{id,body,author,created_at,mine}], total }",
      "url": "https://staging.agentalog.com/api/listings/:id/comments",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/listings/:id/comments",
      "auth": "guest",
      "summary": "Writes a comment on the listing. Cap of 20 per hour per owner.",
      "grupo": "Community",
      "params": {
        "id": {
          "desc": "ID of the listing to comment on."
        }
      },
      "corpo": {
        "body": {
          "tipo": "string",
          "desc": "The comment text.",
          "obrigatorio": true
        }
      },
      "body": {
        "body": "text"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true` when the comment went in."
        },
        "id": {
          "tipo": "string",
          "desc": "ID of the created comment."
        },
        "body": {
          "tipo": "string",
          "desc": "The stored text."
        }
      },
      "erros": {
        "400": "Empty or too long text.",
        "401": null,
        "404": "The listing does not exist.",
        "429": "More than 20 comments in the hour."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/listings/ID/comments -H \"X-Guest-Token: $MR\" -H 'content-type: application/json' -d '{\"body\":\"works well with Claude Code\"}'",
      "returns": "{ ok, id, body }",
      "url": "https://staging.agentalog.com/api/listings/:id/comments",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: mr_…` or `Authorization: Bearer mr_…`. In the browser it also lives in the HttpOnly `guest` cookie, which writes only from this site's exact Origin. A signed-in account (cookie) also works and takes precedence."
    },
    {
      "method": "DELETE",
      "path": "/api/comments/:id",
      "auth": "guest",
      "summary": "Deletes a comment of yours. Someone else's comment answers 404, not 403.",
      "grupo": "Community",
      "desc": "The 404 is on purpose: the API does not confirm that a comment with that id exists if it is not yours.",
      "params": {
        "id": {
          "desc": "Comment ID, from `Comentario.id`.",
          "exemplo": "cm_9f3c2b1d7a4e58b0c2"
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "id": {
          "tipo": "string",
          "desc": "The id that was removed."
        }
      },
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s -XDELETE $ORIGIN/api/comments/CMT_ID -H \"X-Guest-Token: $MR\"",
      "returns": "{ ok, id }",
      "url": "https://staging.agentalog.com/api/comments/:id",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: mr_…` or `Authorization: Bearer mr_…`. In the browser it also lives in the HttpOnly `guest` cookie, which writes only from this site's exact Origin. A signed-in account (cookie) also works and takes precedence."
    },
    {
      "method": "POST",
      "path": "/api/listings/:id/like",
      "auth": "guest",
      "summary": "Likes the listing. Calling again does not add up: the counter counts people.",
      "grupo": "Community",
      "params": {
        "id": {
          "desc": "ID of the listing to like."
        }
      },
      "retorno": "Like",
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s -XPOST $ORIGIN/api/listings/ID/like -H \"X-Guest-Token: $MR\"",
      "returns": "{ ok, liked, likes }",
      "url": "https://staging.agentalog.com/api/listings/:id/like",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: mr_…` or `Authorization: Bearer mr_…`. In the browser it also lives in the HttpOnly `guest` cookie, which writes only from this site's exact Origin. A signed-in account (cookie) also works and takes precedence."
    },
    {
      "method": "DELETE",
      "path": "/api/listings/:id/like",
      "auth": "guest",
      "summary": "Unlikes and gives the point back to the public counter.",
      "grupo": "Community",
      "params": {
        "id": {
          "desc": "ID of the listing to unlike."
        }
      },
      "retorno": "Like",
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s -XDELETE $ORIGIN/api/listings/ID/like -H \"X-Guest-Token: $MR\"",
      "returns": "{ ok, liked, likes }",
      "url": "https://staging.agentalog.com/api/listings/:id/like",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: mr_…` or `Authorization: Bearer mr_…`. In the browser it also lives in the HttpOnly `guest` cookie, which writes only from this site's exact Origin. A signed-in account (cookie) also works and takes precedence."
    },
    {
      "method": "GET",
      "path": "/api/feeds",
      "auth": "none",
      "colecao": {
        "porPagina": 50,
        "anda": "next"
      },
      "summary": "The feed index: RSS, Atom and JSON feeds, OPML reading lists and sites that only become a feed through a bridge.",
      "grupo": "Feeds",
      "desc": "Find feeds by text, format, language and availability. Filter and text search run in the SAME full-text query: values inside one parameter are OR'd, different parameters are AND'd. Without `q` the order is by newest in the index (`recentes`) and `next_cursor` is a keyset — follow `next` to walk everything. With `q` the order is relevance and paging is by `offset`. We index and link; the feeds belong to whoever publishes them.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Free text over the feed name, its description and the domain. Every word must match; accents are ignored.",
          "exemplo": "linux"
        },
        "origem": {
          "tipo": "string",
          "desc": "Where the record comes from. Comma-separated values are OR'd.",
          "valores": [
            "index",
            "blogroll",
            "bridge"
          ]
        },
        "tipo": {
          "tipo": "string",
          "desc": "Feed format. Comma-separated values are OR'd.",
          "valores": [
            "rss2",
            "rss1",
            "atom",
            "json",
            "rss"
          ]
        },
        "midia": {
          "tipo": "string",
          "desc": "Enclosures the feed carries — this is how you find podcasts and video feeds.",
          "valores": [
            "audio",
            "video"
          ]
        },
        "comunidade": {
          "tipo": "string",
          "desc": "Community the publisher belongs to, as the source's bitmask declares it.",
          "valores": [
            "fediverse",
            "indieweb",
            "mastodon",
            "friendica",
            "wordpress",
            "funkwhale",
            "blogroll"
          ]
        },
        "recurso": {
          "tipo": "string",
          "desc": "Namespace seen in the feed: `content` means the whole post travels in the feed, `itunes`/`podcast` mean podcast metadata, `slash` means comment counts.",
          "valores": [
            "content",
            "itunes",
            "podcast",
            "media",
            "slash",
            "wfw",
            "georss"
          ]
        },
        "lista": {
          "tipo": "string",
          "desc": "For OPML lists only: how the list presents itself.",
          "valores": [
            "web",
            "catalogo",
            "planeta"
          ]
        },
        "ano": {
          "tipo": "string",
          "desc": "Year of the newest item the crawler saw. `0` means the source never dated the content. It is a year, not a moving window: the value never drifts.",
          "exemplo": "2026,2025"
        },
        "saude": {
          "tipo": "string",
          "desc": "What our own check saw: `ok` answered, `erro` refused or timed out, `sumiu` returned 404/410. A feed not checked yet matches none of them.",
          "valores": [
            "ok",
            "erro",
            "sumiu"
          ],
          "exemplo": "ok"
        },
        "pais": {
          "tipo": "string",
          "desc": "ISO-3166 alpha-2 of the IP that serves the host, lowercase or uppercase, resolved in the same check.",
          "exemplo": "br,pt"
        },
        "dominio": {
          "tipo": "string",
          "desc": "Exact domain — the fastest way to ask whether a site has a feed."
        },
        "idioma": {
          "tipo": "string",
          "desc": "Language of the site's home page, two or three letters: `pt` matches `pt` and `pt-br`.",
          "exemplo": "pt"
        },
        "imagem": {
          "tipo": "string",
          "desc": "`1` keeps only feeds whose site has a stored preview image (`imagem` is not empty) — the list that looks like a wall of link cards.",
          "valores": [
            "1"
          ]
        },
        "sort": {
          "tipo": "string",
          "desc": "Result order. `recentes` is insertion in the index (what just arrived). `postando` is the newest post first, read from the feed itself (feeds without a dated post are left out). `frequentes` is most posts in the last 30 days first (same). `densidade` is how much item text discovery found — the closest thing to 'this feed has substance'. `dominio` is A–Z by site.",
          "valores": [
            "recentes",
            "postando",
            "frequentes",
            "densidade",
            "dominio",
            "relevancia"
          ],
          "padrao": "relevancia with q, recentes otherwise"
        },
        "cursor": {
          "tipo": "string",
          "desc": "Opaque cursor from `next_cursor` (orders `recentes`, `densidade` and `dominio`). A cursor from another order restarts at the first page."
        },
        "limit": {
          "tipo": "int",
          "desc": "Feeds per page, 1–50.",
          "padrao": 20
        },
        "offset": {
          "tipo": "int",
          "desc": "Offset, capped at 10000. Ignored when `cursor` is present.",
          "padrao": 0
        }
      },
      "retorno": "PaginaDeFeeds",
      "exemplo": "curl -s '$ORIGIN/api/feeds?midia=audio&recurso=itunes&limit=5'",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "returns": "{ items[{id,kind,dominio,url,nome,descricao,tipo,audio,video,comunidade,comunidades,ano,recursos,densidade,itens,saude,pais,site_titulo,site_descricao,site_nome,site_og,site_og_alt,site_cor,site_idioma,idioma_bandeira,icone,imagem,ultimo_post,posts_24h,posts_7d,posts_30d,posts_dias,posts_no_feed,posts_parcial,atividade_em,pagina,api}], limit, offset, next_cursor, next_offset, next, sort, api }",
      "url": "https://staging.agentalog.com/api/feeds",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/feeds/facets",
      "auth": "none",
      "summary": "How many feeds exist in each filter value.",
      "grupo": "Feeds",
      "desc": "Counts reflect the latest catalog update.",
      "retorno": "FacetasDeFeeds",
      "exemplo": "curl -s $ORIGIN/api/feeds/facets",
      "returns": "{ total, facetas, api }",
      "url": "https://staging.agentalog.com/api/feeds/facets",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/feeds/:id",
      "auth": "none",
      "summary": "One feed: address, format, what it carries and where it was found.",
      "grupo": "Feeds",
      "desc": "The same record the HTML page at `/feeds/<id>` shows. 404 when the id is unknown.",
      "params": {
        "id": {
          "tipo": "string",
          "desc": "Feed id, prefix `fd_`.",
          "exemplo": "fd_nytimes_com_1a2b3c4d5e6f7a8b"
        }
      },
      "retorno": "Feed",
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "404": "No feed in this index has that id.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s $ORIGIN/api/feeds/fd_nytimes_com_1a2b3c4d5e6f7a8b",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ id, kind, dominio, url, nome, descricao, tipo, audio, video, comunidade, comunidades, ano, recursos, densidade, itens, saude, pais, site_titulo, site_descricao, site_nome, site_og, site_og_alt, site_cor, site_idioma, idioma_bandeira, icone, imagem, ultimo_post, posts_24h, posts_7d, posts_30d, posts_dias, posts_no_feed, posts_parcial, atividade_em, pagina, api }",
      "url": "https://staging.agentalog.com/api/feeds/:id",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/feeds/:id/items",
      "auth": "none",
      "summary": "The posts of one feed, as our queue read them.",
      "grupo": "Feeds",
      "desc": "Up to 40 posts, in the order the feed publishes them, WITHOUT the body — the body of one post comes from `/items/:ord`. It is OUR copy, read on our own schedule — not the live feed and not a proxy: the only thing this endpoint accepts is an id from this index, never a URL. `lido_em` says when we read it. Empty list when the feed has not been read yet.",
      "params": {
        "id": {
          "tipo": "string",
          "desc": "Feed id, prefix `fd_`.",
          "exemplo": "fd_nytimes_com_1a2b3c4d5e6f7a8b"
        }
      },
      "retorno": "PostsDeFeed",
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "404": "No feed in this index has that id. A feed we know but have not read yet answers 200 with an empty `itens` — the two are different answers on purpose.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s $ORIGIN/api/feeds/fd_nytimes_com_1a2b3c4d5e6f7a8b/items",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ id, itens[{ord,tags,media,comentarios,comentarios_n,titulo,link,quando,autor,resumo,bytes}], lido_em, api }",
      "url": "https://staging.agentalog.com/api/feeds/:id/items",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/feeds/:id/items/:ord",
      "auth": "none",
      "summary": "One post of a feed, with the body — the author's HTML and the same text in Markdown.",
      "grupo": "Feeds",
      "desc": "Two bodies for the same post, both produced when we READ the feed, never at request time: `conteudo_html` keeps the author's formatting through an allowlist (only known tags and attributes survive; script, style, iframe and event handlers are dropped with their content), and `conteudo` is the same text as Markdown — the shape an agent usually wants. Neither can carry script. 404 when the feed or the position is unknown.",
      "params": {
        "id": {
          "tipo": "string",
          "desc": "Feed id, prefix `fd_`.",
          "exemplo": "fd_nytimes_com_1a2b3c4d5e6f7a8b"
        },
        "ord": {
          "tipo": "int",
          "desc": "Position of the post in the feed; 0 is the newest.",
          "exemplo": "0"
        }
      },
      "retorno": "PostDeFeedInteiro",
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "404": "Unknown feed id, or a position this feed does not have.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s $ORIGIN/api/feeds/fd_nytimes_com_1a2b3c4d5e6f7a8b/items/0",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ id, ord, titulo, link, quando, autor, resumo, conteudo_html, conteudo, lido_em, api }",
      "url": "https://staging.agentalog.com/api/feeds/:id/items/:ord",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/indices",
      "auth": "none",
      "summary": "The MCP indexes this catalog reads: credit, license, what each measures, counts and the last round.",
      "grupo": "MCP indexes",
      "desc": "Each index measures something different — one completes an MCP handshake, another reads the last commit, another only discovers that a resource exists — so `mede` comes with every source and every signal. Collected once a day on our own host, raw data kept, and credited on every response: the data is theirs. `coleta.falhou` says the last round failed; the error text stays private.",
      "retorno": "ListaDeIndices",
      "exemplo": "curl -s $ORIGIN/api/indices",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "returns": "{ ok, indices[{id,nome,url,licenca,mede,cadencia_h,sinais,no_catalogo,por_estado,coleta,_links}], _links }",
      "url": "https://staging.agentalog.com/api/indices",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/indices/sinais",
      "auth": "none",
      "summary": "What each MCP index says about one listing of this catalog.",
      "grupo": "MCP indexes",
      "desc": "A signal belongs to a listing only when it is the SAME object: the name in the official MCP registry, the exact remote endpoint URL or the GitHub `owner/repo`, in that order. A shared domain never matches — two servers on one host are different products. Up to 20 signals, one per index and record.",
      "query": {
        "listing": {
          "tipo": "string",
          "desc": "Listing id from `/api/listings`.",
          "exemplo": "mcp_com_stripe_mcp_b890f1d0",
          "obrigatorio": true
        }
      },
      "retorno": "SinaisDoRegistro",
      "erros": {
        "400": "`listing` is missing.",
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s '$ORIGIN/api/indices/sinais?listing=mcp_com_stripe_mcp_b890f1d0'",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ ok, listing, count, sinais[{fonte,credito,mede,kind,nome,descricao,url,repo,estado,estado_na_fonte,motivo,acesso,detalhe,ficha_na_fonte,no_catalogo,medido_em,visto_em}], _links }",
      "url": "https://staging.agentalog.com/api/indices/sinais",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/indices/itens",
      "auth": "none",
      "colecao": {
        "porPagina": 50,
        "anda": "offset"
      },
      "summary": "Browse the signals, including servers this catalog does not list yet.",
      "grupo": "MCP indexes",
      "desc": "Newest change first. `casou=0` is what the indexes know and the catalog does not — the list to look at before submitting a server. Filters are AND'd.",
      "query": {
        "fonte": {
          "tipo": "string",
          "desc": "Only the signals of this index — `/api/indices` says what each one measures.",
          "valores": [
            "wellknown",
            "agent_tools",
            "nerq",
            "truespar",
            "neuronto",
            "paygent",
            "hultra"
          ]
        },
        "estado": {
          "tipo": "string",
          "desc": "The state in this catalog's words.",
          "valores": [
            "vivo",
            "fora",
            "parado",
            "abandonado",
            "apagado",
            "desconhecido"
          ]
        },
        "casou": {
          "tipo": "string",
          "desc": "`1` only signals matched to a listing, `0` only unmatched.",
          "valores": [
            "0",
            "1"
          ]
        },
        "q": {
          "tipo": "string",
          "desc": "Substring of the name, the URL or the repository.",
          "exemplo": "postgres"
        },
        "limit": {
          "tipo": "int",
          "desc": "Signals per page, 1–50.",
          "padrao": 20
        },
        "offset": {
          "tipo": "int",
          "desc": "Offset, capped at 50000.",
          "padrao": 0
        }
      },
      "retorno": "PaginaDeSinais",
      "exemplo": "curl -s '$ORIGIN/api/indices/itens?fonte=truespar&estado=fora&casou=1&limit=5'",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "returns": "{ ok, total, count, items[{fonte,credito,mede,kind,nome,descricao,url,repo,estado,estado_na_fonte,motivo,acesso,detalhe,ficha_na_fonte,no_catalogo,medido_em,visto_em}], _links }",
      "url": "https://staging.agentalog.com/api/indices/itens",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/listings",
      "auth": "session_ou_x402",
      "summary": "Registers an MCP server, a skill or a plugin in the catalog. It comes in as `pending`.",
      "grupo": "Publish",
      "desc": "A person reviews it by hand; poll `status_api` (`GET /api/listings/:id/status`, no credential) to learn the decision. Two doors to the same action. Human with a session: free, 1 per day, at most 3 in the queue. Agent (with or without a guest): **402 with `accepts[]`**, $0.10 — pay and repeat. For a skill, the `SKILL.md` URL is enough; the rest is checked. **Validates before charging:** a refused body (400) and an exhausted quota (429) come BEFORE the 402, so no payment settles for a listing already known not to get in. A valid body without payment keeps receiving the 402 with the price.",
      "corpo": {
        "kind": {
          "tipo": "string",
          "desc": "What is being registered.",
          "valores": [
            "mcp",
            "skill",
            "plugin",
            "okf"
          ],
          "obrigatorio": true
        },
        "url": {
          "tipo": "string",
          "desc": "MCP endpoint, SKILL.md URL, the plugin's repository or the OKF bundle's `index.md`. For an OKF bundle on a domain you control, `POST /api/okf/ping` is free.",
          "obrigatorio": true
        },
        "name": {
          "tipo": "string",
          "desc": "Display name; without it, taken from the source."
        },
        "tagline": {
          "tipo": "string",
          "desc": "One line saying what it is for."
        },
        "body": {
          "tipo": "string",
          "desc": "Long description, optional."
        },
        "category": {
          "tipo": "string",
          "desc": "Category so the listing shows up under the right filter."
        }
      },
      "body": {
        "kind": "mcp",
        "category": "tools",
        "name": "Name",
        "tagline": "One line",
        "url": "https://example.com/mcp"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true` when the request went in."
        },
        "id": {
          "tipo": "string",
          "desc": "ID of the created listing."
        },
        "status": {
          "tipo": "string",
          "desc": "Always `pending`: everything goes through the queue before turning live."
        },
        "status_api": {
          "tipo": "string",
          "desc": "Where to poll for the review, with no credential (`GET /api/listings/:id/status`)."
        }
      },
      "erros": {
        "400": "`kind` or `url` missing, invalid URL, URL that does not answer or refused field.",
        "402": null,
        "429": "1 per day, at most 3 pending — applies to both doors, and is checked before charging.",
        "502": "The payment settled and the write failed. The body carries `transaction`: keep it and talk to support."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/listings -H \"X-PAYMENT: $PAYMENT\" -H 'content-type: application/json' -d '{\"kind\":\"mcp\",\"url\":\"https://example.com/mcp\",\"name\":\"My MCP\"}'",
      "returns": "{ ok, id, status, status_api }",
      "url": "https://staging.agentalog.com/api/listings",
      "auth_detail": "Two doors to the SAME action: a human with the account session (cookie; free, within the quota) or an agent paying x402 (`X-PAYMENT`). A guest token is neither required nor blocks the paid path."
    },
    {
      "method": "PATCH",
      "path": "/api/listings/:id",
      "auth": "session",
      "summary": "Edits a listing of yours. Changing the URL sends it back to the queue.",
      "grupo": "Publish",
      "desc": "The URL is what moderation looks at; swapping it after approval would bypass the queue, so the listing goes back to `pending`.",
      "params": {
        "id": {
          "desc": "ID of the listing to edit."
        }
      },
      "corpo": {
        "name": {
          "tipo": "string",
          "desc": "New display name."
        },
        "tagline": {
          "tipo": "string",
          "desc": "New summary line."
        },
        "body": {
          "tipo": "string",
          "desc": "New long description."
        },
        "category": {
          "tipo": "string",
          "desc": "New category."
        },
        "url": {
          "tipo": "string",
          "desc": "New URL — changing this sends the listing back to `pending`."
        }
      },
      "body": {
        "tagline": "…"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "id": {
          "tipo": "string",
          "desc": "ID of the edited listing."
        },
        "status": {
          "tipo": "string",
          "desc": "State after the edit; back to `pending` if the URL changed."
        }
      },
      "erros": {
        "400": "Invalid field in the body.",
        "401": null,
        "404": "The listing is not yours or does not exist."
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/listings/ID\", {method: \"PATCH\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({tagline: \"now with SSE support\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok, id, status }",
      "url": "https://staging.agentalog.com/api/listings/:id",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/me/listings",
      "auth": "session",
      "summary": "The owner's listings in any state, including pending and hidden.",
      "grupo": "Publish",
      "desc": "It is the only route that shows what is not live yet — the public mosaic never does.",
      "retorno": {
        "items": {
          "tipo": "Anuncio[]",
          "desc": "The account's listings, in any state."
        }
      },
      "erros": [
        401
      ],
      "exemplo": "await fetch(\"$ORIGIN/api/me/listings\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ items[{id,kind,category,name,tagline,body,url,status,origin,origin_id,install,source,transporte,ns,versao,oficial_status,repo_host,topico,linguagem,licenca,repo_topics,repo_slug,stars,forks,prs_abertos,pushed_at,repo_estado,likes,comments,visits,created_at,updated_at,mine,api,go,comments_api,readme_api?,historico?,readme_fonte?,readme_bytes,readme_sha,readme_em,payload}] }",
      "url": "https://staging.agentalog.com/api/me/listings",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/me",
      "auth": "session",
      "summary": "The session's account and, for the admin, the load state.",
      "desc": "The account is the global account; `user.id` is its id — the same id that owns the listings, likes and comments made with it, and the guest's after the claim.",
      "grupo": "Account",
      "retorno": {
        "user": {
          "tipo": "Conta",
          "desc": "The person who owns the session."
        },
        "profile": {
          "tipo": "object",
          "desc": "Global profile: `name`, `locale`, `timeZone`, `theme`, `revision`."
        },
        "admin": {
          "tipo": "bool",
          "desc": "Whether this account is the `ADMIN_EMAIL`."
        },
        "carga": {
          "tipo": "Carga",
          "desc": "State of the load sources; admin only.",
          "opcional": true
        }
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "exemplo": "await fetch(\"$ORIGIN/api/me\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ user{id,email}, profile, admin, carga?{fontes,falhas,runs,orcamento} }",
      "url": "https://staging.agentalog.com/api/me",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/me/ui",
      "auth": "session",
      "summary": "The owner's screen preferences: search, filter, sort and theme.",
      "grupo": "Account",
      "desc": "Exists so what the person set up survives an F5 and reopening the app on another device. A refresh is not a new screen — see AGENTS-UI.md. A guest has none: without an account there is nobody to give the data back to later, so the guest stays in the browser's `localStorage` only.",
      "retorno": "PreferenciasUi",
      "erros": [
        401
      ],
      "exemplo": "await fetch(\"$ORIGIN/api/me/ui\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ prefs, api }",
      "url": "https://staging.agentalog.com/api/me/ui",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "PUT",
      "path": "/api/me/ui",
      "auth": "session",
      "summary": "Stores the owner's screen preferences, replacing the previous ones.",
      "grupo": "Account",
      "desc": "It is PUT and not PATCH on purpose: the client sends the whole screen state, not a delta. Cap of 8 KB — this is a screen preference, not a blob store.",
      "corpo": {
        "prefs": {
          "tipo": "object",
          "desc": "The interface state to keep. Opaque to the server: any JSON within the cap works.",
          "obrigatorio": true
        }
      },
      "body": {
        "prefs": {
          "q": "postgres",
          "kind": "mcp",
          "sort": "likes",
          "tema": "escuro"
        }
      },
      "retorno": "Ok",
      "erros": {
        "400": "Body that is not JSON (`bad_json`) or without the `prefs` key (`prefs`).",
        "401": null,
        "405": "Method other than GET or PUT on this route.",
        "413": "Preferences above the 8 KB cap (`grande`)."
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/me/ui\", {method: \"PUT\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({prefs: {sort: \"likes\"}})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/me/ui",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/auth/bootstrap",
      "auth": "none",
      "grupo": "Account",
      "summary": "Prepare the browser for global sign-in.",
      "desc": "Sets a host-only HttpOnly browser cookie. CSRF is bound to the current session. No CORS.",
      "retorno": {
        "csrf": {
          "tipo": "string",
          "desc": "X-CSRF-Token"
        },
        "context": {
          "tipo": "string",
          "desc": "Opaque view context, also in X-MM-Context; not a credential / contexto opaco da vista, não é credencial."
        }
      },
      "erros": {
        "400": "invalid_request",
        "403": "invalid_origin / invalid_csrf",
        "503": "auth_unavailable: a sessão anterior é preservada / the previous session is preserved"
      },
      "returns": "{ csrf, context }",
      "url": "https://staging.agentalog.com/api/auth/bootstrap",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/account/profile",
      "auth": "session",
      "grupo": "Account",
      "exemplo": "await fetch(\"$ORIGIN/api/account/profile\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "summary": "Read your global profile.",
      "desc": "Reads current preferences from the account. Edit them on your account page; products never own a separate profile.",
      "retorno": {
        "_texto": "{profile:{name,locale,timeZone,theme,revision}}"
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "returns": "{profile:{name,locale,timeZone,theme,revision}}",
      "url": "https://staging.agentalog.com/api/account/profile",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/account/avatar",
      "auth": "session",
      "grupo": "Account",
      "exemplo": "await fetch(\"$ORIGIN/api/account/avatar\", {credentials: \"same-origin\"}).then(r => {if (!r.ok) throw new Error(\"HTTP \" + r.status); return r.blob();});",
      "exemploLinguagem": "js",
      "summary": "Read your global profile photo.",
      "desc": "Private WebP, up to 64 KiB, no cache. Change it on your account. No user ID or object URL accepted.",
      "retorno": {
        "_texto": "image/webp; Cache-Control: no-store"
      },
      "erros": {
        "401": "invalid_session",
        "404": "not_found: no photo / sem foto",
        "503": "auth_unavailable"
      },
      "returns": "image/webp; Cache-Control: no-store",
      "url": "https://staging.agentalog.com/api/account/avatar",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "POST",
      "path": "/api/auth/logout",
      "auth": "session",
      "grupo": "Account",
      "exemplo": "// Execute no console da página do produto / Run in the product page console.\n(async () => {\n  const origin = \"$ORIGIN\";\n  const {csrf} = await fetch(origin + \"/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(origin + \"/api/auth/logout\", {\n    method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({})\n  });\n  if (!r.ok) throw new Error(\"Auth HTTP \" + r.status);\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "summary": "Revoke this product session.",
      "desc": "Bootstrap/CSRF must belong to this browser and session. Other product sessions remain active.",
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_request",
        "403": "invalid_origin / invalid_csrf",
        "503": "auth_unavailable: a sessão anterior é preservada / the previous session is preserved"
      },
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/auth/logout",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/account/keys",
      "auth": "session",
      "grupo": "Account",
      "summary": "List your API keys in this product.",
      "desc": "Never returns the key itself: name, last 4 characters, organization, creation, last use (hourly) and whether it still works.",
      "retorno": {
        "keys": {
          "tipo": "object[]",
          "desc": "`id`, `name`, `organizationId`, `last4`, `createdAt`, `lastUsedAt`, `revokedAt`, `active` (false when revoked or stopped by a password change / ending all sessions)."
        }
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "exemplo": "await fetch(\"$ORIGIN/api/account/keys\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ keys }",
      "url": "https://staging.agentalog.com/api/account/keys",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "POST",
      "path": "/api/account/keys/create",
      "auth": "session",
      "grupo": "Account",
      "summary": "Create an API key for agents and scripts.",
      "desc": "Needs a sign-in in the last 5 minutes; an organization key also needs a second factor in the session and the owner/admin role with this product enabled. At most 10 live keys per account and product. The key (`secret`) is returned ONCE.",
      "corpo": {
        "name": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Up to 60 characters."
        },
        "organizationId": {
          "tipo": "string",
          "nulo": true,
          "obrigatorio": true,
          "desc": "`null` for an account key."
        }
      },
      "body": {
        "name": "agent",
        "organizationId": null
      },
      "retorno": {
        "key": {
          "tipo": "object",
          "desc": "`id`, `name`, `organizationId`, `last4`, `createdAt`."
        },
        "secret": {
          "tipo": "string",
          "desc": "`mmk_…`, shown once."
        }
      },
      "erros": {
        "400": "invalid_key_name / invalid_organization",
        "401": "invalid_session / reauth_required",
        "403": "invalid_origin / invalid_csrf / organization_forbidden / organization_mfa_required",
        "409": "key_limit_reached",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/keys/create\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({name: \"agent\", organizationId: null})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ key, secret }",
      "url": "https://staging.agentalog.com/api/account/keys/create",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "POST",
      "path": "/api/account/keys/revoke",
      "auth": "session",
      "grupo": "Account",
      "summary": "Revoke one of your API keys.",
      "desc": "Stops the key at once. Repeating is harmless.",
      "corpo": {
        "id": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "The key `id`."
        }
      },
      "body": {
        "id": "…"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_key_id",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "404": "key_not_found",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/keys/revoke\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({id: \"…\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/account/keys/revoke",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "POST",
      "path": "/api/auth/claim",
      "auth": "session",
      "grupo": "Account",
      "summary": "Moves what the guest created to the signed-in account: its listings, likes and comments.",
      "desc": "Bootstrap/CSRF of this browser required; the page does it right after sign-in. Only what the guest still owns moves, in one transaction, and anything that collides with what the account already has stays with the guest. What the guest bought moves too. An old unsigned token that owns nothing here is refused. Repeating it is harmless (moves zero).",
      "corpo": {
        "guest_token": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Guest `mr_…`; omitted, the `guest` cookie of this browser."
        }
      },
      "body": {},
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Whether the guest was recognized and moved."
        },
        "claimed": {
          "tipo": "object",
          "desc": "`product.movidos` (rows moved, per table), `product.apagados` (guest duplicates dropped) and `product.direitos` (purchases moved)."
        }
      },
      "erros": {
        "400": "invalid_product_claim / invalid_body",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "409": "unknown_guest (em `claimed.reason` / in `claimed.reason`)",
        "503": "product_claim_pending / auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/auth/claim\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: \"{}\"});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok, claimed }",
      "url": "https://staging.agentalog.com/api/auth/claim",
      "auth_detail": "Global account: the HttpOnly session cookie of this domain, set when you sign in at `/conta/global`. Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. A write with the cookie of an ended session answers 401 `session_ended` — sign in again; it never turns into the guest. No bearer token is issued to humans."
    },
    {
      "method": "GET",
      "path": "/api/billing",
      "auth": "none",
      "summary": "x402 configuration in force and the agent prices for contact and publishing.",
      "grupo": "Billing",
      "retorno": "Billing",
      "exemplo": "curl -s $ORIGIN/api/billing",
      "returns": "{ provider, mode, network, chain_id, pay_to, homolog, dev, dev_gate, gratis?, facilitator, asset, asset_address, faucet, wallets, product, prices{contact_agent_usd,listing_agent_usd} }",
      "url": "https://staging.agentalog.com/api/billing",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/contact",
      "auth": "none",
      "summary": "Talks to support: a human solves Turnstile, an agent pays $0.10 in x402.",
      "grupo": "Billing",
      "desc": "The first agent message is free; after that the backoff is 60s doubling up to a 1-hour cap, announced in `Retry-After`.",
      "corpo": {
        "name": {
          "tipo": "string",
          "desc": "What to call the person writing.",
          "obrigatorio": true
        },
        "email": {
          "tipo": "string",
          "desc": "Where to reply.",
          "obrigatorio": true
        },
        "message": {
          "tipo": "string",
          "desc": "What you want to say.",
          "obrigatorio": true
        },
        "form_ts": {
          "tipo": "int",
          "desc": "When the form was opened; the anti-robot of the human path, and only it requires this."
        },
        "cf_turnstile_response": {
          "tipo": "string",
          "desc": "Turnstile response; present only on the human path."
        },
        "tipo": {
          "tipo": "string",
          "desc": "Proposal: `patrocinio`, `parceria` or `anuncio`. Turns on the fields below."
        },
        "empresa": {
          "tipo": "string",
          "desc": "Who is proposing, when it is a company."
        },
        "site": {
          "tipo": "string",
          "desc": "Website of who is proposing."
        },
        "orcamento": {
          "tipo": "string",
          "desc": "`ate_100`, `100_500`, `500_2000`, `2000_mais` or `a_combinar`."
        },
        "espaco": {
          "tipo": "string[]",
          "desc": "Placement ids from `GET /api/partners`, up to 6."
        },
        "duracao": {
          "tipo": "string",
          "desc": "Exposure in days: `30`, `90` or `365`."
        },
        "pagamento": {
          "tipo": "string",
          "desc": "`usdc`, `deposito` or `a_combinar`."
        }
      },
      "body": {
        "name": "…",
        "email": "a@example.com",
        "message": "…"
      },
      "retorno": "Ok",
      "erros": {
        "400": "Required field missing.",
        "402": null,
        "429": "Agent backoff: wait for `Retry-After`."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/contact -H \"X-PAYMENT: $PAYMENT\" -H 'content-type: application/json' -d '{\"name\":\"Agent\",\"email\":\"a@example.com\",\"message\":\"Hello\"}'",
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/contact",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/visit",
      "auth": "none",
      "summary": "Ping from the interface that increments the day's visits. Agents need not call it.",
      "grupo": "Billing",
      "desc": "Smoke does not count: `X-MM-Smoke`, User-Agent `mm-smoke` or `smoke: true` in the body come in as `counted: false`.",
      "corpo": {
        "p": {
          "tipo": "string",
          "desc": "Path of the visited page."
        },
        "smoke": {
          "tipo": "bool",
          "desc": "`true` marks the call as a test and it does not enter the count."
        }
      },
      "body": {
        "p": "/"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "counted": {
          "tipo": "bool",
          "desc": "Whether the visit entered the day's count."
        },
        "reason": {
          "tipo": "string",
          "desc": "Why it did not count, when `counted` is `false`.",
          "opcional": true
        }
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/visit -H 'content-type: application/json' -d '{\"p\":\"/\",\"smoke\":true}'",
      "returns": "{ ok, counted, reason? }",
      "url": "https://staging.agentalog.com/api/visit",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/erro-cliente",
      "auth": "none",
      "summary": "Browser error report, sent by the interface itself. Agents need not call it.",
      "grupo": "Operations",
      "desc": "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.",
      "corpo": {
        "code": {
          "tipo": "string",
          "desc": "Failure code, `UI-` + letters/digits (`UI-JS-001` global error, `UI-PROMESSA-001`, `UI-RECURSO-001`, `UI-CSP-001`, `UI-APP-001` app report).",
          "obrigatorio": true
        },
        "phase": {
          "tipo": "string",
          "desc": "Where it broke, lowercase: `global`, `promessa`, `script`, `load_list`…",
          "obrigatorio": true
        },
        "path": {
          "tipo": "string",
          "desc": "Path of the open page, without query."
        },
        "message": {
          "tipo": "string",
          "desc": "Error message, up to 2000 characters."
        },
        "stack": {
          "tipo": "string",
          "desc": "Stack trace, up to 12000 characters."
        },
        "source": {
          "tipo": "string",
          "desc": "Originating script; only its path is kept."
        },
        "line": {
          "tipo": "int",
          "desc": "Line in the originating script."
        },
        "column": {
          "tipo": "int",
          "desc": "Column in the originating script."
        },
        "visivel": {
          "tipo": "bool",
          "desc": "Whether the tab was visible when it broke."
        }
      },
      "body": {
        "code": "UI-APP-001",
        "phase": "carregar_lista",
        "path": "/",
        "message": "lista 500"
      },
      "retorno": {
        "_texto": "204 with no body, always — an invalid, repeated or over-cap report also gets 204."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/erro-cliente -H 'content-type: application/json' -d '{\"code\":\"UI-APP-001\",\"phase\":\"carregar_lista\",\"path\":\"/\",\"message\":\"lista 500\"}'",
      "returns": "204 with no body, always — an invalid, repeated or over-cap report also gets 204.",
      "url": "https://staging.agentalog.com/api/erro-cliente",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/pagamento/aberto",
      "auth": "none",
      "statusOk": 202,
      "summary": "The interface reports a visible payment prompt. Agents must not call this route.",
      "grupo": "Operations",
      "desc": "An empty same-origin report, sent automatically when a payment prompt becomes visible. It starts no payment, grants no access and receives no identity or credentials. It writes no database row per report. Counts events, not unique people. The private operator dashboard separates API payment requests and browser payment views per UTC day; the two counts may overlap.",
      "headers": {
        "Origin": {
          "tipo": "string",
          "desc": "The page origin, identical to this route's origin.",
          "obrigatorio": true
        },
        "Sec-Fetch-Site": {
          "tipo": "string",
          "desc": "`same-origin`, set by the browser.",
          "obrigatorio": true
        },
        "X-MM-Payment-View": {
          "tipo": "string",
          "desc": "`1`, set by the shared component.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "_texto": "202 with no body when accepted; 204 when ignored. Always no-store."
      },
      "returns": "202 with no body when accepted; 204 when ignored. Always no-store.",
      "url": "https://staging.agentalog.com/api/pagamento/aberto",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/vitrine",
      "auth": "none",
      "grupo": "Public stats",
      "summary": "The product's public numbers: traffic, agents, usage and reliability, no money.",
      "desc": "Projection published hourly by the house collector, rounded to two significant digits; `null` is a missing measurement, never zero. 15-minute cache with ETag (`If-None-Match` → 304). There is no way to send numbers through this route: publishing belongs to the collector, with its own token.",
      "retorno": {
        "v": {
          "tipo": "int",
          "desc": "Contract version (1)."
        },
        "produto": {
          "tipo": "string",
          "desc": "Product id."
        },
        "publicado": {
          "tipo": "bool",
          "desc": "`false` before the collector's first publication; then only these five keys come."
        },
        "atualizado_em": {
          "tipo": "string",
          "desc": "When the collector published (ISO 8601).",
          "nulo": true
        },
        "stale": {
          "tipo": "bool",
          "desc": "`true` when the projection is older than 26 h."
        },
        "nome": {
          "tipo": "string",
          "desc": "Product name.",
          "opcional": true
        },
        "desde": {
          "tipo": "string",
          "desc": "First day the series covers.",
          "nulo": true,
          "opcional": true
        },
        "fuso": {
          "tipo": "string",
          "desc": "Time zone of the days (`UTC`).",
          "opcional": true
        },
        "hoje": {
          "tipo": "object",
          "desc": "Today: pages by class (human, AI, bot), API calls by class, machine-surface reads and product usage.",
          "opcional": true
        },
        "dias": {
          "tipo": "object[]",
          "desc": "Up to 31 days, oldest first: `dia`, `paginas`, `api`, `api_ia`, `maquina`, `visitantes`, `uso`.",
          "opcional": true
        },
        "janelas": {
          "tipo": "object",
          "desc": "7- and 30-day sums (`d7`, `d30`).",
          "opcional": true
        },
        "visitantes": {
          "tipo": "object",
          "desc": "Unique visitors at the edge over 7 days.",
          "opcional": true
        },
        "pessoas": {
          "tipo": "object",
          "desc": "GA4 when available: users, sessions, countries, devices and who arrived from AI.",
          "nulo": true,
          "opcional": true
        },
        "agentes": {
          "tipo": "object",
          "desc": "The AI agents and bots that read the most, 7 days.",
          "opcional": true
        },
        "superficies": {
          "tipo": "object",
          "desc": "Reads of OKF, llms, well-known, OpenAPI and MCP over 7 days.",
          "opcional": true
        },
        "mcp": {
          "tipo": "object",
          "desc": "MCP calls over 7 days.",
          "opcional": true
        },
        "uso": {
          "tipo": "object",
          "desc": "Real product usage per resource: label, today, 7 and 30 days.",
          "opcional": true
        },
        "contas": {
          "tipo": "object",
          "desc": "Users and guests.",
          "nulo": true,
          "opcional": true
        },
        "confiabilidade": {
          "tipo": "object",
          "desc": "Share of requests without 5xx over 7 days, and the live build.",
          "opcional": true
        },
        "catalogo": {
          "tipo": "object",
          "desc": "Size of the catalog, when the product has one.",
          "nulo": true,
          "opcional": true
        },
        "apoio": {
          "tipo": "object",
          "desc": "Impressions and clicks per sponsor, when any.",
          "opcional": true
        }
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine",
      "returns": "{ v, produto, publicado, atualizado_em, stale, nome?, desde?, fuso?, hoje?, dias?, janelas?, visitantes?, pessoas?, agentes?, superficies?, mcp?, uso?, contas?, confiabilidade?, catalogo?, apoio? }",
      "url": "https://staging.agentalog.com/api/vitrine",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/vitrine/operador",
      "auth": "none",
      "grupo": "Public stats",
      "summary": "The product's full document on the operator panel — operator token only.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — the operator class.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "produto": {
          "tipo": "string",
          "desc": "Product id."
        },
        "atualizado_em": {
          "tipo": "string",
          "desc": "When the collector published.",
          "nulo": true
        },
        "operador": {
          "tipo": "object",
          "desc": "The collector's full document, with what the public projection leaves out.",
          "nulo": true
        }
      },
      "erros": {
        "401": "No token, wrong token or a token of another class.",
        "503": "Worker without `METRICS_TOKEN` or without the control plane."
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine/operador -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ produto, atualizado_em, operador }",
      "url": "https://staging.agentalog.com/api/vitrine/operador",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/vitrine/painel",
      "auth": "none",
      "grupo": "Public stats",
      "summary": "The whole house panel, in the shape the gm reads — operator token only.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — the operator class.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "apps": {
          "tipo": "object[]",
          "desc": "One operator document per product, ordered by id."
        },
        "updated": {
          "tipo": "string",
          "desc": "When the collector closed the round.",
          "opcional": true
        },
        "totals": {
          "tipo": "object",
          "desc": "House totals.",
          "opcional": true
        }
      },
      "erros": {
        "401": "No token, wrong token or a token of another class.",
        "503": "Worker without `METRICS_TOKEN` or without the control plane."
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine/painel -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ apps, updated?, totals? }",
      "url": "https://staging.agentalog.com/api/vitrine/painel",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/vitrine/cursores",
      "auth": "none",
      "grupo": "Public stats",
      "summary": "The resolved-error cursor per product (`borda`, `cli`) — operator token only.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — the operator class.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "_texto": "JSON: `{ [product]: { borda?: ISO, cli?: ISO } }`; empty is `{}`."
      },
      "erros": {
        "401": "No token, wrong token or a token of another class.",
        "503": "Worker without `METRICS_TOKEN` or without the control plane."
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine/cursores -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "JSON: `{ [product]: { borda?: ISO, cli?: ISO } }`; empty is `{}`.",
      "url": "https://staging.agentalog.com/api/vitrine/cursores",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/partners",
      "auth": "none",
      "grupo": "Partnership",
      "summary": "Partnership, sponsorship and advertising: the product's placements with a suggested price, the public numbers next to them and how to propose.",
      "desc": "Information on request, no activation: placements from the house catalogue priced in USD per 30 days (90 and 365 days discounted), sponsors in effect, an excerpt of `/api/vitrine`, the house wallet (USDC on Base) and the contact path — bank deposit, PIX or invoice are arranged in the reply. Cached for 1 hour.",
      "retorno": {
        "status": {
          "tipo": "string",
          "desc": "`sob_consulta`: information and proposal, no activation and no charge."
        },
        "produto": {
          "tipo": "string",
          "desc": "Product name."
        },
        "idioma": {
          "tipo": "string",
          "desc": "Language of the texts (the product's)."
        },
        "titulo": {
          "tipo": "string",
          "desc": "Title of the offer."
        },
        "descricao": {
          "tipo": "string",
          "desc": "One sentence about the offer."
        },
        "publico": {
          "tipo": "string",
          "desc": "Who uses the product — the audience a sponsor reaches."
        },
        "modalidades": {
          "tipo": "object[]",
          "desc": "`{ id, nome }`: patrocinio, parceria, anuncio."
        },
        "placements": {
          "tipo": "object[]",
          "desc": "The product's placements: `id`, `nome`, `onde`, `formato`, `exclusivo`, `medicao`, `price_usd_30d` (suggested; `null` is on request), `exposure[{ dias, price_usd }]` for 30, 90 and 365 days, `disponivel`."
        },
        "house_bundle": {
          "tipo": "object",
          "desc": "The house bundle: footer and agent mention across the ten products, discounted."
        },
        "parcerias": {
          "tipo": "string[]",
          "desc": "Partnership ideas the product is open to discuss."
        },
        "current_sponsors": {
          "tipo": "object[]",
          "desc": "Sponsors in effect: `id`, `nome`, `url`, `frase`, `espacos`, `ate`."
        },
        "stats": {
          "tipo": "object",
          "desc": "Excerpt of the public numbers (`hoje`, `janelas`, `agentes`, `confiabilidade`) and the `link` to `/api/vitrine`; `publicado: false` before the first publication."
        },
        "payment": {
          "tipo": "object",
          "desc": "How to pay: `rede`, `chain_id`, `ativo`, `pay_to`, `eip681` (the house wallet, when declared), `alternativas` and the `nota` — bank deposit, PIX or invoice in the reply."
        },
        "contact": {
          "tipo": "object",
          "desc": "`email`, `form_url`, `api_url` (`POST /api/contact` where the handler exists), `campos` (required), `campos_proposta` (the optional proposal fields, each with its accepted values), `price_agent_usd`, `message_template`, `instructions`."
        },
        "politica": {
          "tipo": "object",
          "desc": "Placement label, refused sectors, prepayment, deadlines."
        },
        "_links": {
          "tipo": "object",
          "desc": "`self`, `stats`, `page` (`null` until the page exists), `contact`, `casa` (the same path on the ten products)."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/partners",
      "returns": "{ status, produto, idioma, titulo, descricao, publico, modalidades, placements, house_bundle, parcerias, current_sponsors, stats, payment, contact, politica, _links }",
      "url": "https://staging.agentalog.com/api/partners",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/metrics",
      "auth": "none",
      "summary": "Metrics of the last 7 days. With the operator token, includes payments.",
      "grupo": "Billing",
      "desc": "Without credentials it returns visits, usage and accounts. With `METRICS_TOKEN` as Bearer it adds `payments` — and only on Base mainnet, because staging numbers on a finance panel mislead.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` to include the finance block.",
          "obrigatorio": false
        }
      },
      "retorno": "Metricas",
      "exemplo": "curl -s $ORIGIN/api/metrics -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments? }",
      "url": "https://staging.agentalog.com/api/metrics",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/listings/:id/status",
      "auth": "none",
      "summary": "Moderation state of a listing — how the submitter polls for approval, with no credential.",
      "grupo": "Publish",
      "desc": "Every submission is born `pending` and a person approves it by hand; this is the receipt you poll after `POST /api/listings` (its response carries this URL as `status_api`). Only the decision comes back, never the unreviewed content: the id (`lst_…`, unguessable) is all it takes, and the page itself keeps its rule — owner only until it is public. Answers are cached for 60 s per point of presence: poll every few minutes, not every second.",
      "params": {
        "id": {
          "desc": "Listing ID, from the `id` of the `POST /api/listings` response."
        }
      },
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "Listing ID."
        },
        "status": {
          "tipo": "string",
          "desc": "Moderation state. `pending` is waiting; `live` and `low` are approved; `hidden` and `blocked` are not published.",
          "valores": [
            "pending",
            "live",
            "low",
            "hidden",
            "blocked"
          ]
        },
        "public": {
          "tipo": "bool",
          "desc": "`true` when the listing is reachable in the catalog (`live` or `low`)."
        },
        "message": {
          "tipo": "string",
          "desc": "What the state means and what to do next."
        },
        "reason": {
          "tipo": "string",
          "desc": "Why it was hidden or blocked, when the moderator left a reason. Absent otherwise.",
          "opcional": true
        },
        "api": {
          "tipo": "string",
          "desc": "The listing's page (`GET /api/listings/:id`): the owner reads it with the token that created it; everybody else once it is public."
        },
        "status_api": {
          "tipo": "string",
          "desc": "This URL, to poll again."
        }
      },
      "erros": {
        "404": "No listing with this id."
      },
      "exemplo": "curl -s $ORIGIN/api/listings/ID/status",
      "returns": "{ id, status, public, message, reason?, api, status_api }",
      "url": "https://staging.agentalog.com/api/listings/:id/status",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/okf/ping",
      "auth": "none",
      "statusOk": 202,
      "summary": "Submits OKF bundles from a domain you control, using the IndexNow protocol.",
      "grupo": "Publish",
      "desc": "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. The same queue is served by `POST https://okfindex.com/api/ping`, the index's own home — search, bundle cards and statistics live there.",
      "corpo": {
        "host": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "The host that owns the bundles."
        },
        "key": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "8 to 128 characters of [a-zA-Z0-9-]."
        },
        "keyLocation": {
          "tipo": "string",
          "desc": "Where the key file lives. Defaults to `https://<host>/<key>.txt`; must be on `host`."
        },
        "urlList": {
          "tipo": "string[]",
          "obrigatorio": true,
          "desc": "Bundle `index.md` URLs. https, on `host`, ending in .md. No fixed path: the spec defines no discovery convention."
        }
      },
      "body": {
        "host": "example.com",
        "key": "a1b2c3d4e5f60718",
        "urlList": [
          "https://example.com/okf/index.md"
        ]
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "The submission was queued."
        },
        "estado": {
          "tipo": "string",
          "desc": "Always `pendente`: the key has not been checked yet."
        },
        "recebidos": {
          "tipo": "int",
          "desc": "How many distinct URLs entered the queue."
        },
        "chave_em": {
          "tipo": "string",
          "desc": "Where we will look for the key file. Check it if you are unsure."
        }
      },
      "erros": {
        "400": "Malformed body, `host`/`key` invalid or `urlList` missing.",
        "422": "A URL is not https, is not .md, or does not belong to `host` — `keyLocation` on another host too.",
        "429": "This host reached 200 bundles for the UTC day."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/okf/ping -H 'content-type: application/json' -d '{\"host\":\"example.com\",\"key\":\"a1b2c3d4e5f60718\",\"urlList\":[\"https://example.com/okf/index.md\"]}'",
      "returns": "{ ok, estado, recebidos, chave_em }",
      "url": "https://staging.agentalog.com/api/okf/ping",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/bundles",
      "auth": "none",
      "colecao": {
        "porPagina": 24,
        "teto": 1000,
        "anda": "next_offset"
      },
      "summary": "Paginated search of the index: every live OKF bundle, from GitHub and from live domains.",
      "grupo": "Index",
      "desc": "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/okf/stats` has it.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Free text over name, tagline, description and origin identifier.",
          "exemplo": "agent"
        },
        "origin": {
          "tipo": "string",
          "desc": "Provenance: found by the GitHub sweep, or submitted by a domain.",
          "valores": [
            "github",
            "domain"
          ]
        },
        "repo": {
          "tipo": "string",
          "desc": "Only bundles of one repository, `owner/repo` (case-insensitive).",
          "exemplo": "fastendpoints/fastendpoints"
        },
        "version": {
          "tipo": "string",
          "desc": "Only bundles declaring one of these `okf_version` values; comma-separated, up to 5.",
          "exemplo": "0.1,0.2"
        },
        "concept": {
          "tipo": "string",
          "desc": "Text in the indexed root content, including listed concept names and summaries (first 1000 characters); up to 80 characters."
        },
        "concepts": {
          "tipo": "string",
          "desc": "Number of entries listed by the root. Up to 5 comma-separated bands: 0,1-5,6-20,21-100,101+."
        },
        "type": {
          "tipo": "string",
          "desc": "Type declared by the root, not the types of every concept. Up to 5 comma-separated values, 40 characters each."
        },
        "license": {
          "tipo": "string",
          "desc": "Repository license. Up to 5 comma-separated values, 40 characters each."
        },
        "language": {
          "tipo": "string",
          "desc": "Only bundles whose repository language is one of these; comma-separated, up to 5 (GitHub bundles).",
          "exemplo": "TypeScript,Go"
        },
        "sort": {
          "tipo": "string",
          "desc": "Result order: arrival, last content change, name or repository stars.",
          "valores": [
            "recent",
            "updated",
            "name",
            "stars"
          ],
          "padrao": "recent"
        },
        "limit": {
          "tipo": "int",
          "desc": "Bundles per page, at most 100.",
          "padrao": 24
        },
        "offset": {
          "tipo": "int",
          "desc": "How many bundles to skip. Use `next_offset` from the previous response; the list ends at 1000.",
          "padrao": 0
        }
      },
      "retorno": "PaginaDeBundles",
      "exemplo": "curl -s '$ORIGIN/api/bundles?q=agent&sort=stars&limit=5'",
      "returns": "{ items[{id,name,tagline,description,okf_version,concepts,concept_list,type,index_url,page_url,source,repo,indexed_at,updated_at,api}], limit, offset, next_offset, next }",
      "url": "https://staging.agentalog.com/api/bundles",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/bundles/:id",
      "auth": "none",
      "summary": "One bundle's card, by id.",
      "grupo": "Index",
      "desc": "`live` and `low` (example or fixture bundles kept out of the search) both answer here.",
      "params": {
        "id": {
          "desc": "Bundle id, the `id` of every item in the list.",
          "exemplo": "okf-fastendpoints"
        }
      },
      "retorno": "Bundle",
      "erros": {
        "404": "No bundle with that id, or it is not public."
      },
      "exemplo": "curl -s $ORIGIN/api/bundles/<id>",
      "returns": "{ id, name, tagline, description, okf_version, concepts, concept_list[{name,url,summary}], 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 }",
      "url": "https://staging.agentalog.com/api/bundles/:id",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/okf/stats",
      "auth": "none",
      "summary": "Size of the index by provenance, and when it last changed.",
      "grupo": "Index",
      "retorno": "IndexStats",
      "exemplo": "curl -s $ORIGIN/api/okf/stats",
      "returns": "{ total, by_origin, by_version[{v,n}], by_type[{v,n}], by_concepts[{v,n}], by_license[{v,n}], by_language[{v,n}], last_update }",
      "url": "https://staging.agentalog.com/api/okf/stats",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/volatil",
      "auth": "none",
      "grupo": "Catalog",
      "summary": "Fresh download, install and version counters for up to 100 listings.",
      "desc": "The catalog stores the values seen at the last real change of a listing; counters and package versions change over time. These values may be cached for up to 15 minutes; `gerado_em` gives their reference date. Listings without a record are simply absent. `GET /api/listings/:id` already applies these values on top of the record.",
      "query": {
        "ids": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Comma-separated listing ids, at most 100."
        }
      },
      "retorno": {
        "itens": {
          "tipo": "object",
          "desc": "`{id: {downloads?, installs?, version?, pacotes?}}` — `pacotes` maps `registry:identifier` to its version."
        },
        "gerado_em": {
          "tipo": "string",
          "desc": "When the oldest slice read was generated (UTC)."
        },
        "ttl_s": {
          "tipo": "int",
          "desc": "How long a slice stays in the edge cache."
        }
      },
      "erros": {
        "400": "`ids` missing, invalid, or more than 100."
      },
      "exemplo": "curl -s '$ORIGIN/api/volatil?ids=skl_a,skl_b'",
      "returns": "{ itens, gerado_em, ttl_s }",
      "url": "https://staging.agentalog.com/api/volatil",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/admin/volatil",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Publishes one group of updated counters.",
      "desc": "CARGA_TOKEN only. One slice = 1/256 of the ids (by hash), whole; submit only slices whose content changed. Nothing here touches the catalog database — that is the point.",
      "corpo": {
        "fatia": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Two hex digits; every id in `itens` must hash to it."
        },
        "gerado_em": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "UTC instant the slice was built."
        },
        "itens": {
          "tipo": "object",
          "obrigatorio": true,
          "desc": "`{id: record}`, at most 5000 ids and 1 MB."
        }
      },
      "body": {
        "fatia": "0a",
        "gerado_em": "2026-09-08 12:00:00",
        "itens": {
          "skl_a": {
            "downloads": 138,
            "version": "1.1"
          }
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Stored."
        },
        "fatia": {
          "tipo": "string",
          "desc": "The slice stored."
        },
        "itens": {
          "tipo": "int",
          "desc": "Records in it."
        }
      },
      "erros": {
        "400": "Malformed slice, id outside the slice, or above the ceilings.",
        "401": "CARGA_TOKEN required.",
        "503": "Object storage not configured."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/volatil -H \"Authorization: Bearer $CARGA_TOKEN\" -d @fatia.json",
      "returns": "{ ok, fatia, itens }",
      "url": "https://staging.agentalog.com/api/admin/volatil",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/sitemap",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Receives one shard of the listings sitemap (or its manifest) for publication.",
      "desc": "CARGA_TOKEN only. Submit catalog shards (up to 50,000 listings each, ordered by id) and sends only the shard whose content changed, then the manifest (how many shards, when). The Worker serves `/sitemap-listings.xml` (index) and `/sitemap-listings-N.xml` (shard) from that storage, with cache at the edge; the catalog database is never read for it.",
      "corpo": {
        "parte": {
          "tipo": "int",
          "desc": "Shard number, 1-based (at most 200). Omit when sending the manifest."
        },
        "gerado_em": {
          "tipo": "string",
          "desc": "UTC instant the shard was built."
        },
        "urls": {
          "tipo": "object[]",
          "desc": "`{id, lastmod?}` per listing, at most 50,000; `lastmod` is the listing's `updated_at`."
        },
        "manifesto": {
          "tipo": "object",
          "desc": "`{partes, gerado_em}` — sent once after the shards; replaces the previous manifest."
        }
      },
      "body": {
        "parte": 1,
        "gerado_em": "2026-09-13 12:00:00",
        "urls": [
          {
            "id": "mcp_x",
            "lastmod": "2026-09-10 08:00:00"
          }
        ]
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Stored."
        },
        "parte": {
          "tipo": "int",
          "desc": "The shard stored (absent for the manifest).",
          "opcional": true
        },
        "urls": {
          "tipo": "int",
          "desc": "Listings in it (absent for the manifest).",
          "opcional": true
        },
        "manifesto": {
          "tipo": "object",
          "desc": "The manifest stored (absent for a shard).",
          "opcional": true
        }
      },
      "erros": {
        "400": "Malformed shard or manifest, invalid id, or above the ceilings.",
        "401": "CARGA_TOKEN required.",
        "503": "Object storage not configured."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/sitemap -H \"Authorization: Bearer $CARGA_TOKEN\" -d @parte-1.json",
      "returns": "{ ok, parte?, urls?, manifesto? }",
      "url": "https://staging.agentalog.com/api/admin/sitemap",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "GET",
      "path": "/api/listings/:id/history",
      "auth": "none",
      "summary": "Timeline of the listing's repository: the last events (stale, gone, renamed, README or manifest changed).",
      "grupo": "Catalog",
      "desc": "The listing page carries the same list as `historico`; updates may be cached for up to 15 minutes. An empty list means no change since the series began — the listing still exists. Stale means no push for 12 months. Reading this endpoint does not refresh the record.",
      "params": {
        "id": {
          "desc": "Listing ID, from `Anuncio.id`."
        }
      },
      "retorno": "Historico",
      "erros": {
        "401": "Invalid MAT pass.",
        "402": "Free allowance or MAT credits exhausted; buy a package.",
        "404": "The listing does not exist or is not visible.",
        "409": "Retry conflict or pending read.",
        "413": "Basic read exceeds 1 MiB.",
        "429": "Temporary reading capacity.",
        "503": "Origin or payment verification temporarily unavailable."
      },
      "exemplo": "curl -s $ORIGIN/api/listings/ID/history",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "returns": "{ id, historico, gerado_em, ttl_s, api }",
      "url": "https://staging.agentalog.com/api/listings/:id/history",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/contadores",
      "auth": "none",
      "summary": "Likes, comments and visits of every listing that has any, read from where they are written.",
      "grupo": "Catalog",
      "desc": "Counters include visits, likes and comments and may take up to five minutes to reach catalog pages. Only listings with a counter above zero are returned. Smoke traffic never counts. Cached for 60 seconds.",
      "retorno": "Contadores",
      "exemplo": "curl -s $ORIGIN/api/contadores",
      "returns": "{ gerado_em, total, truncado, itens }",
      "url": "https://staging.agentalog.com/api/contadores",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/fila",
      "auth": "none",
      "summary": "The public snapshot of the enrichment queue: how much of the catalog has been checked.",
      "grupo": "Operation",
      "desc": "It is public because it is about the catalog's health, not about anyone: aggregate numbers only, no identifiable listing.",
      "retorno": "EstadoFila",
      "exemplo": "curl -s $ORIGIN/api/fila",
      "returns": "{ ok, fila{total,concluidos,vencidos,com_falha,processados,estados,motivos} }",
      "url": "https://staging.agentalog.com/api/fila",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/admin/fila",
      "auth": "token",
      "summary": "The enrichment robot pushes the snapshot of its own queue here.",
      "grupo": "Operation",
      "desc": "Robot credential only: this does not write to the catalog, so there is no reason to accept admin.",
      "corpo": {
        "fila": {
          "tipo": "object",
          "desc": "The queue snapshot: totals, states and reasons.",
          "obrigatorio": true
        }
      },
      "body": {
        "fila": {
          "total": 20182,
          "concluidos": 11675
        }
      },
      "retorno": "Ok",
      "erros": {
        "400": "Body without `fila`.",
        "401": null
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/fila -H \"Authorization: Bearer $TOKEN_ROBO\" -H 'content-type: application/json' -d '{\"fila\":{}}'",
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/admin/fila",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/repos",
      "auth": "token",
      "summary": "The enricher writes here what it found out about a repository: stars, forks, state.",
      "grupo": "Operation",
      "desc": "Accepts the enricher's credential OR the admin's — the robot has its own, with less privilege, and the admin gets in to operate by hand without depending on the robot. The Worker collects nothing: it only stores what was already checked outside it.",
      "corpo": {
        "itens": {
          "tipo": "object[]",
          "desc": "Up to 500 checked repositories with repo_slug, stars, forks, PRs, pushed_at and state. Optional listing_ids is an array of up to 50 listing IDs (1–160 letters, digits, underscore or hyphen); only matching listings of that repository are updated. An empty array stores only the repository fact. Omit it only for legacy fanout, still subject to the daily budget.",
          "obrigatorio": true
        }
      },
      "body": {
        "itens": [
          {
            "repo_slug": "x/y",
            "stars": 120,
            "repo_estado": "ativo"
          }
        ]
      },
      "retorno": "Ok",
      "erros": {
        "400": "Body without `itens` or malformed item.",
        "401": "Neither the enricher's nor the admin's credential.",
        "429": "Daily publication budget exhausted; retain pending facts."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/repos -H \"Authorization: Bearer $TOKEN_ROBO\" -H 'content-type: application/json' -d '{\"itens\":[]}'",
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/admin/repos",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "GET",
      "path": "/api/admin/listings",
      "auth": "token",
      "summary": "The moderation queue. Without a filter, brings what is pending.",
      "grupo": "Operation",
      "desc": "Accepts `ADMIN_TOKEN` as Bearer or the `ADMIN_EMAIL` session.",
      "query": {
        "status": {
          "tipo": "string",
          "desc": "Which state to list.",
          "valores": [
            "pending",
            "live",
            "hidden",
            "blocked"
          ],
          "padrao": "pending"
        }
      },
      "retorno": {
        "items": {
          "tipo": "Anuncio[]",
          "desc": "The listings in that state."
        }
      },
      "erros": [
        401
      ],
      "exemplo": "curl -s '$ORIGIN/api/admin/listings?status=pending' -H \"Authorization: Bearer $ADMIN_TOKEN\"",
      "returns": "{ items[{id,kind,category,name,tagline,body,url,status,origin,origin_id,install,source,transporte,ns,versao,oficial_status,repo_host,topico,linguagem,licenca,repo_topics,repo_slug,stars,forks,prs_abertos,pushed_at,repo_estado,likes,comments,visits,created_at,updated_at,mine,api,go,comments_api,readme_api?,historico?,readme_fonte?,readme_bytes,readme_sha,readme_em,payload}] }",
      "url": "https://staging.agentalog.com/api/admin/listings",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/listings/:id",
      "auth": "token",
      "summary": "Decides the fate of a listing in the queue: approve, hide or block.",
      "grupo": "Operation",
      "desc": "A submitter with an account gets one e-mail per decision (the decision, the reason and the page or the receipt); repeating the same state sends nothing. A guest or agent owner has no e-mail and polls `GET /api/listings/:id/status`.",
      "params": {
        "id": {
          "desc": "ID of the listing to moderate."
        }
      },
      "corpo": {
        "action": {
          "tipo": "string",
          "desc": "What to do with the listing.",
          "valores": [
            "approve",
            "hide",
            "block"
          ],
          "obrigatorio": true
        },
        "reason": {
          "tipo": "string",
          "desc": "Why, for whoever submitted: it comes back in `GET /api/listings/:id/status`. Required for `block`, optional for `hide`, ignored for `approve` (which clears an earlier reason). Up to 300 characters."
        },
        "fix": {
          "tipo": "object",
          "desc": "Corrections applied together with `approve`, any of `name`, `tagline`, `body`, `category`, with the same validation as a submission. `url` and `kind` are refused: a new URL is what sends a listing back to the queue."
        }
      },
      "body": {
        "action": "hide",
        "reason": "The URL has answered 404 since yesterday."
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "status": {
          "tipo": "string",
          "desc": "The state the listing ended up in."
        },
        "reason": {
          "tipo": "string",
          "desc": "The reason stored with the decision; empty when none."
        }
      },
      "erros": {
        "400": "`action` outside the list; `reason` missing on `block` or above 300 characters; `fix` outside `approve`; `fix_url` (URL or kind inside the fix); or the refused field of the fix (`name`, `tagline`, `category`, `golpe`).",
        "401": null,
        "404": null
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/listings/ID -H \"Authorization: Bearer $ADMIN_TOKEN\" -H 'content-type: application/json' -d '{\"action\":\"approve\"}'",
      "returns": "{ ok, status, reason }",
      "url": "https://staging.agentalog.com/api/admin/listings/:id",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "GET",
      "path": "/api/admin/carga",
      "auth": "token",
      "summary": "State of the catalog's load sources: last batch, count and failures.",
      "grupo": "Operation",
      "desc": "Accepts `ADMIN_TOKEN` as Bearer or the `ADMIN_EMAIL` session.",
      "query": {
        "fonte": {
          "tipo": "string",
          "desc": "Restricts to one source, e.g. `official_mcp`."
        }
      },
      "retorno": "Carga",
      "erros": [
        401
      ],
      "exemplo": "curl -s $ORIGIN/api/admin/carga -H \"Authorization: Bearer $ADMIN_TOKEN\"",
      "returns": "{ fontes, falhas, runs, orcamento }",
      "url": "https://staging.agentalog.com/api/admin/carga",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/carga",
      "auth": "token",
      "summary": "Requests an update or marks a failure alert as seen.",
      "desc": "run/reset enqueue a request for the next scheduled operation. They do not run synchronously.",
      "grupo": "Operation",
      "corpo": {
        "action": {
          "tipo": "string",
          "desc": "What to do with the source.",
          "valores": [
            "run",
            "visto",
            "reset"
          ],
          "obrigatorio": true
        },
        "fonte": {
          "tipo": "string",
          "desc": "Which source to load or mark, e.g. `official_mcp`."
        }
      },
      "body": {
        "action": "run",
        "fonte": "official_mcp"
      },
      "retorno": "Ok",
      "erros": {
        "400": "`action` outside the list or unknown source.",
        "401": null
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/carga -H \"Authorization: Bearer $ADMIN_TOKEN\" -H 'content-type: application/json' -d '{\"action\":\"run\",\"fonte\":\"official_mcp\"}'",
      "returns": "{ ok }",
      "url": "https://staging.agentalog.com/api/admin/carga",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "GET",
      "path": "/api/admin/okf/pendentes",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Reads the queue of OKF bundles submitted through `POST /api/okf/ping`.",
      "desc": "CARGA_TOKEN only. Up to 50 submissions, oldest first. The edge never fetches a key file or a bundle: submissions require key verification before reading the submitter's host — otherwise a stranger could make us fetch arbitrary URLs.",
      "retorno": {
        "pendentes": {
          "tipo": "object[]",
          "desc": "{bundle_url, host, chave, chave_url} still waiting for key verification."
        },
        "lote": {
          "tipo": "int",
          "desc": "Batch ceiling; a full page may have more pending items."
        }
      },
      "erros": {
        "401": "CARGA_TOKEN required."
      },
      "exemplo": "curl -s $ORIGIN/api/admin/okf/pendentes -H \"Authorization: Bearer $CARGA_TOKEN\"",
      "returns": "{ pendentes, lote }",
      "url": "https://staging.agentalog.com/api/admin/okf/pendentes",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/okf/pendentes",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Records verification of submitted bundles.",
      "desc": "CARGA_TOKEN only. Changes the QUEUE, never the catalog: an approved bundle reaches the mosaic through the normal catalog difference, because two doors writing listings would be two truths. A network failure is not a verdict — the submission stays pending and comes back next round.",
      "corpo": {
        "resultados": {
          "tipo": "object[]",
          "obrigatorio": true,
          "desc": "{bundle_url, estado: verificado|recusado, motivo}. At most 50; `motivo` is chave|bundle|okf_version."
        }
      },
      "body": {
        "resultados": [
          {
            "bundle_url": "https://example.com/okf/index.md",
            "estado": "verificado"
          }
        ]
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "The batch was applied."
        },
        "marcados": {
          "tipo": "int",
          "desc": "How many queue rows were touched."
        }
      },
      "erros": {
        "400": "Missing `resultados`, more than 50, or an unknown state.",
        "401": "CARGA_TOKEN required."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/okf/pendentes -H \"Authorization: Bearer $CARGA_TOKEN\" -H 'content-type: application/json' -d '{\"resultados\":[]}'",
      "returns": "{ ok, marcados }",
      "url": "https://staging.agentalog.com/api/admin/okf/pendentes",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/feeds",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Applies prepared feed-index differences for publication.",
      "desc": "Requires CARGA_TOKEN. Maximum 100 items and 2 MB. A daily budget slice of its own stops publication with 429 (`alvo: \"feeds\"`) without holding the catalog back; unconfirmed items remain pending.",
      "corpo": {
        "itens": {
          "tipo": "object[]",
          "obrigatorio": true,
          "desc": "Each delta has id, novo, and either valores (changed columns only) or remove:true."
        },
        "contagens": {
          "tipo": "object[]",
          "desc": "Optional `{ chave, n }` list with the count per facet value, computed on the collector."
        }
      },
      "body": {
        "itens": []
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "The complete batch was accepted."
        },
        "aceitos": {
          "tipo": "int",
          "desc": "Accepted items, including idempotent retries."
        },
        "recusados": {
          "tipo": "int",
          "desc": "Zero on success; invalid batches fail in full."
        }
      },
      "erros": {
        "400": "Invalid delta or facet count.",
        "401": "CARGA_TOKEN required.",
        "413": "More than 100 items or a body over 2 MB.",
        "429": "Daily feed slice exhausted; retain pending items."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/feeds -H \"Authorization: Bearer $CARGA_TOKEN\" -d @lote.json",
      "returns": "{ ok, aceitos, recusados }",
      "url": "https://staging.agentalog.com/api/admin/feeds",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/catalogo",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Applies prepared catalog differences for publication.",
      "desc": "Requires CARGA_TOKEN. Imported sources only; no SQL, community records or user fields. Maximum 25 items and 2 MB. An atomic daily budget stops publication with 429; retain unconfirmed differences.",
      "corpo": {
        "itens": {
          "tipo": "object[]",
          "obrigatorio": true,
          "desc": "Each delta has id, origin, origin_id, novo, valores (changed catalog columns only), optional prepared pacotes and owner for new rows."
        }
      },
      "body": {
        "itens": []
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "The complete batch was accepted."
        },
        "aceitos": {
          "tipo": "int",
          "desc": "Accepted items, including idempotent retries."
        },
        "recusados": {
          "tipo": "int",
          "desc": "Zero on success; invalid batches fail in full."
        }
      },
      "erros": {
        "400": "Invalid delta.",
        "401": "CARGA_TOKEN required.",
        "409": "Identity differs from destination.",
        "413": "Batch or body too large.",
        "429": "Daily publication budget exhausted; `alvo` names the slice that ran out (`catalogo` or `okf`, each with its own cap)."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/catalogo -H \"Authorization: Bearer $CARGA_TOKEN\" -H 'content-type: application/json' -d '{\"itens\":[]}'",
      "returns": "{ ok, aceitos, recusados }",
      "url": "https://staging.agentalog.com/api/admin/catalogo",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/readmes",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Stores documentation for listings without a repository.",
      "desc": "Requires CARGA_TOKEN. The listing exposes the document with attribution. Unchanged text is not written again. Maximum 20 items and 2 MB.",
      "corpo": {
        "itens": {
          "tipo": "object[]",
          "obrigatorio": true,
          "desc": "{listing_id, fonte: npm|pypi, readme} — README of 1 to 200,000 characters; no repeated listing_id."
        }
      },
      "body": {
        "itens": [
          {
            "listing_id": "mcp_x",
            "fonte": "npm",
            "readme": "# X"
          }
        ]
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "The batch was processed."
        },
        "aceitos": {
          "tipo": "int",
          "desc": "READMEs stored (new or changed)."
        },
        "iguais": {
          "tipo": "int",
          "desc": "Unchanged READMEs: nothing written."
        },
        "recusados": {
          "tipo": "string[]",
          "desc": "listing_ids unknown to the catalog; the rest of the batch is applied."
        }
      },
      "erros": {
        "400": "Malformed item.",
        "401": "CARGA_TOKEN required.",
        "413": "More than 20 items or body over 2 MB.",
        "429": "Daily publication budget exhausted; retain pending documents.",
        "503": "R2 not configured: nothing indexed."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/readmes -H \"Authorization: Bearer $CARGA_TOKEN\" -H 'content-type: application/json' -d '{\"itens\":[]}'",
      "returns": "{ ok, aceitos, iguais, recusados }",
      "url": "https://staging.agentalog.com/api/admin/readmes",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/fts",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Indexes one page of live listings into the full-text search index.",
      "desc": "Requires CARGA_TOKEN. Pages by rowid: `apos` is the last rowid already indexed, `limite` the page size (≤ 500). Each page reserves 5 write units per listing in the daily catalog budget before writing; 429 means try tomorrow. An empty page marks the index ready (`fts:pronto`) and the search switches from LIKE to the index.",
      "corpo": {
        "apos": {
          "tipo": "int",
          "obrigatorio": true,
          "desc": "Last rowid already indexed; 0 to start."
        },
        "limite": {
          "tipo": "int",
          "desc": "Page size, 1–500 (default 500)."
        }
      },
      "body": {
        "apos": 0,
        "limite": 500
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "The page was processed."
        },
        "indexados": {
          "tipo": "int",
          "desc": "Listings written to the index in this page."
        },
        "ultimo": {
          "tipo": "int",
          "desc": "Last rowid indexed — send it back as `apos`."
        },
        "pronto": {
          "tipo": "bool",
          "desc": "`true` when there was nothing left: the index covers the catalog."
        }
      },
      "erros": {
        "400": "Invalid page.",
        "401": "CARGA_TOKEN required.",
        "429": "Daily catalog budget exhausted."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/fts -H \"Authorization: Bearer $CARGA_TOKEN\" -H 'content-type: application/json' -d '{\"apos\":0,\"limite\":500}'",
      "returns": "{ ok, indexados, ultimo, pronto }",
      "url": "https://staging.agentalog.com/api/admin/fts",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "GET",
      "path": "/api/admin/carga/c3",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Reads pending operator commands and an indexed community delta.",
      "desc": "CARGA_TOKEN only. Up to 100 community rows ordered by (updated_at,id), older than one minute. Imported catalog rows are never read. A full page advances to its last row; a short page advances to ate with empty apos.",
      "query": {
        "desde": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "UTC cursor, YYYY-MM-DD HH:mm:ss."
        },
        "apos": {
          "tipo": "string",
          "desc": "ID after the last received row; empty for a new time boundary."
        }
      },
      "retorno": {
        "pedidos": {
          "tipo": "object[]",
          "desc": "Commands {fonte,id,acao}; restricted to the operation service."
        },
        "comunidade": {
          "tipo": "object[]",
          "desc": "Changed {id,source,status,updated_at} records."
        },
        "ate": {
          "tipo": "string",
          "desc": "Exclusive UTC upper bound of the feed."
        }
      },
      "erros": {
        "400": "Invalid cursor.",
        "401": "CARGA_TOKEN required."
      },
      "exemplo": "curl -sG $ORIGIN/api/admin/carga/c3 --data-urlencode \"desde=2026-09-06 00:00:00\" -H \"Authorization: Bearer $CARGA_TOKEN\"",
      "returns": "{ pedidos, comunidade, ate }",
      "url": "https://staging.agentalog.com/api/admin/carga/c3",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/admin/carga/c3",
      "auth": "token",
      "grupo": "Operation",
      "summary": "Publishes source status and acknowledges operator commands completed by the operation service.",
      "desc": "CARGA_TOKEN only. Up to 12 statuses and acknowledgements. A retry with the same run ID does not rewrite status; an old acknowledgement cannot erase a newer command.",
      "corpo": {
        "estados": {
          "tipo": "object[]",
          "obrigatorio": true,
          "desc": "Source run summaries: fonte,id,status,cursor,updated_since,erro,pages,imported,skipped,more,started_at,finished_at."
        },
        "aceites": {
          "tipo": "object[]",
          "obrigatorio": true,
          "desc": "Completed command {fonte,id} pairs."
        }
      },
      "body": {
        "estados": [],
        "aceites": []
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Accepted."
        },
        "estados": {
          "tipo": "int",
          "desc": "Accepted statuses."
        },
        "aceites": {
          "tipo": "int",
          "desc": "Accepted command acknowledgements."
        }
      },
      "erros": {
        "400": "Invalid status or acknowledgement.",
        "401": "CARGA_TOKEN required.",
        "429": "Daily budget exhausted."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/admin/carga/c3 -H \"Authorization: Bearer $CARGA_TOKEN\" -H 'content-type: application/json' -d '{\"estados\":[],\"aceites\":[]}'",
      "returns": "{ ok, estados, aceites }",
      "url": "https://staging.agentalog.com/api/admin/carga/c3",
      "auth_detail": "Operator token `ADMIN_TOKEN` or `METRICS_TOKEN` as Bearer. The load routes also accept the enricher's credential, which has less privilege — see each endpoint."
    },
    {
      "method": "POST",
      "path": "/api/credito",
      "auth": "none",
      "summary": "Top up prepaid credit: pay once with x402 and get the token that debits on any API of the house.",
      "grupo": "Credit",
      "query": {
        "usd": {
          "tipo": "int",
          "desc": "Package: 1, 5, 10 ou 25 dollars.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "token": {
          "tipo": "string",
          "desc": "Bearer token for the balance (`cred_…`). Shown ONCE — it cannot be recovered."
        },
        "saldo_usd": {
          "tipo": "string",
          "desc": "Credited balance."
        },
        "guarde": {
          "tipo": "string",
          "desc": "Warning that the token is the bearer of the credit."
        },
        "usar": {
          "tipo": "string",
          "desc": "How to present the token on paid routes."
        },
        "saldo_em": {
          "tipo": "string",
          "desc": "Where to check balance and statement."
        }
      },
      "erros": {
        "400": "Package outside the list (1, 5, 10 ou 25).",
        "402": "Unpaid — the body carries the x402 `accepts[]`."
      },
      "exemplo": "curl -s -XPOST '$ORIGIN/api/credito?usd=10'",
      "returns": "{ token, saldo_usd, guarde, usar, saldo_em }",
      "url": "https://staging.agentalog.com/api/credito",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/credito",
      "auth": "credito",
      "summary": "Credit balance and statement — the latest movements, without returning the token.",
      "grupo": "Credit",
      "retorno": {
        "saldo_micros": {
          "tipo": "int",
          "desc": "Balance in micro-dollars (1e-6 USD)."
        },
        "saldo_usd": {
          "tipo": "string",
          "desc": "Formatted balance."
        },
        "criado_em": {
          "tipo": "string",
          "desc": "When the credit was opened."
        },
        "movimentos": {
          "tipo": "object[]",
          "desc": "Recent credits and debits, with product and resource."
        }
      },
      "erros": {
        "401": "No token, or unknown token."
      },
      "exemplo": "curl -s $ORIGIN/api/credito -H 'Authorization: Bearer cred_…'",
      "returns": "{ saldo_micros, saldo_usd, criado_em, movimentos }",
      "url": "https://staging.agentalog.com/api/credito",
      "auth_detail": "Prepaid credit token in `Authorization: Bearer cred_…` (or the `X-Credito` header). Not an account: it is a bearer of balance."
    },
    {
      "path": "/api/acesso",
      "auth": "none",
      "grupo": "API access",
      "retorno": "ApiAccess",
      "method": "GET",
      "summary": "Discover the monthly data package or inspect a private purchase.",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        }
      },
      "erros": {
        "400": "Invalid pass.",
        "404": "Unknown purchase or wrong owner.",
        "503": "Purchases disabled."
      },
      "exemplo": "curl -s $ORIGIN/api/acesso",
      "desc": "Catalog discovery and ordinary browsing are free. GPTBot, ClaudeBot, CCBot, Meta-ExternalAgent, Amazonbot, AhrefsBot and MJ12bot share a daily allowance of 1,000 reads per crawler family. Further reads require a MAT package: US$1 for 1,000 reads, valid for 30 days, without automatic renewal. Send X-API-Pass on reads. The MAT balance is separate from the company, address and procurement indexes.",
      "returns": "{ offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
      "url": "https://staging.agentalog.com/api/acesso",
      "auth_detail": "Public, no credential."
    },
    {
      "path": "/api/acesso",
      "auth": "none",
      "grupo": "API access",
      "retorno": "ApiAccess",
      "method": "POST",
      "summary": "Buy 1000 basic data reads for US$1, valid for 30 days.",
      "desc": "Catalog discovery and ordinary browsing are free. GPTBot, ClaudeBot, CCBot, Meta-ExternalAgent, Amazonbot, AhrefsBot and MJ12bot share a daily allowance of 1,000 reads per crawler family. Further reads require a MAT package: US$1 for 1,000 reads, valid for 30 days, without automatic renewal. Send X-API-Pass on reads. The MAT balance is separate from the company, address and procurement indexes.",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying.",
          "obrigatorio": true
        },
        "X-Credito": {
          "tipo": "string",
          "desc": "Existing prepaid credit token; alternative to x402."
        },
        "Authorization": {
          "tipo": "string",
          "desc": "Bearer cred_… alternative to X-Credito."
        },
        "X-PAYMENT": {
          "tipo": "string",
          "desc": "Signed x402 authorization from the 402 quote, maximum 16 KiB."
        },
        "PAYMENT-SIGNATURE": {
          "tipo": "string",
          "desc": "Alternative name for X-PAYMENT."
        },
        "X-API-Transaction": {
          "tipo": "string",
          "desc": "Confirmed Base transaction hash for reconciliation with the original pass and signed payment. Never creates another charge."
        }
      },
      "erros": {
        "400": "Missing or invalid pass/payment.",
        "401": "Invalid prepaid credit.",
        "402": "Payment required: x402 accepts[] and prepaid-credit instructions.",
        "409": "Payment pending; retain the same pass and do not pay again.",
        "429": "Purchase attempt limit; respect Retry-After.",
        "503": "Payment unavailable or pending reconciliation."
      },
      "exemplo": "curl -s -X POST \"$ORIGIN/api/acesso\" -H \"X-API-Pass: $API_PASS\"",
      "returns": "{ offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
      "url": "https://staging.agentalog.com/api/acesso",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/coleta/readme/:arquivo",
      "grupo": "Catalog",
      "auth": "none",
      "summary": "Read a collected README as Markdown by its published object path.",
      "desc": "Same MAT read allowance and pass. Prefer /api/listings/:id/readme (also available through MCP) for metadata and the historical R2 fallback. This raw route only serves objects already present on the catalog origin.",
      "params": {
        "arquivo": {
          "tipo": "string",
          "desc": "Published relative README path, e.g. owner/repository.md.",
          "obrigatorio": true
        }
      },
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Optional retry key, up to 80 ASCII characters; same read for five minutes."
        }
      },
      "retorno": {
        "_texto": "README Markdown (text/markdown); a successful basic read is at most 1 MiB."
      },
      "erros": {
        "401": "Invalid pass.",
        "402": "Read allowance or credit exhausted.",
        "404": "README absent.",
        "413": "Read too large.",
        "503": "Origin unavailable."
      },
      "exemplo": "curl -s \"$ORIGIN/coleta/readme/owner/repository.md\" -H \"X-API-Pass: $API_PASS\"",
      "returns": "README Markdown (text/markdown); a successful basic read is at most 1 MiB.",
      "url": "https://staging.agentalog.com/coleta/readme/:arquivo",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/uso",
      "grupo": "API access",
      "auth": "none",
      "summary": "Read the remaining MAT balance without consuming credit.",
      "retorno": "MatUsage",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "MAT-only private pass: mat_<32 random hex>_<64 random hex>. Generate and save before buying.",
          "obrigatorio": true
        }
      },
      "erros": {
        "401": "Missing or invalid pass.",
        "402": "Purchase pending or expired.",
        "503": "Origin unavailable."
      },
      "exemplo": "curl -s \"$ORIGIN/api/uso\" -H \"X-API-Pass: $API_PASS\"",
      "returns": "{ id, credits, used, remaining, expires_at, active }",
      "url": "https://staging.agentalog.com/api/uso",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/pricing",
      "auth": "none",
      "grupo": "Discovery",
      "summary": "Current prices and free allowances.",
      "retorno": {
        "product": {
          "tipo": "string",
          "desc": "Product name."
        },
        "quota": {
          "tipo": "PaymentQuota",
          "desc": "Public allowances and current list prices; not personal usage."
        },
        "pricing": {
          "tipo": "string",
          "desc": "Absolute URL of the current price list."
        },
        "billing": {
          "tipo": "string",
          "desc": "Absolute URL of payment discovery or the existing billing summary."
        },
        "api_index": {
          "tipo": "string",
          "desc": "Absolute URL of the API catalog."
        }
      },
      "erros": {
        "405": "Use GET or HEAD."
      },
      "exemplo": "curl -s $ORIGIN/api/pricing",
      "returns": "{ product, quota{free,paid,how_to_pay,live,free_now?,trial?}, pricing, billing, api_index }",
      "url": "https://staging.agentalog.com/api/pricing",
      "auth_detail": "Public, no credential."
    }
  ],
  "quota": {
    "free": [
      {
        "o_que": "ordinary catalog browsing and discovery",
        "limite": "identified crawlers: 1,000 reads/day per family",
        "janela": null
      },
      {
        "o_que": "like, comment and hop with a guest token",
        "limite": "no quota",
        "janela": null
      },
      {
        "o_que": "register with an e-mail account",
        "limite": "1 per day, max. 3 in the queue",
        "janela": null
      }
    ],
    "paid": [
      {
        "o_que": "1,000 MAT catalog reads for 30 days; separate balance; GET/POST /api/acesso",
        "price_usd": 1
      },
      {
        "o_que": "register as an agent (with or without a guest token)",
        "price_usd": 0.1
      },
      {
        "o_que": "agent contact",
        "price_usd": 0.1
      }
    ],
    "how_to_pay": "Catalog discovery and ordinary browsing are free. GPTBot, ClaudeBot, CCBot, Meta-ExternalAgent, Amazonbot, AhrefsBot and MJ12bot share a daily allowance of 1,000 reads per crawler family. Further reads require a MAT package: US$1 for 1,000 reads, valid for 30 days, without automatic renewal. Send X-API-Pass on reads. The MAT balance is separate from the company, address and procurement indexes. Publishing without the account session answers **402** with `accepts[]` (x402, USDC on Base). Pay and repeat the same call with `X-PAYMENT`. A guest token does NOT remove the option to pay.",
    "live": "https://staging.agentalog.com/api/billing",
    "free_now": [
      "listing_agent"
    ]
  },
  "mcp": {
    "endpoint": "https://staging.agentalog.com/mcp",
    "transport": "streamable-http",
    "tools": 29,
    "note": "Plugs straight into the MCP client; nothing to install. Tools = the operations below."
  },
  "quickstart": [
    "GET https://staging.agentalog.com/api/listings — live mosaic (each item carries the destination URL)",
    "GET https://staging.agentalog.com/v0.1/servers — MCP subregistry (official spec)",
    "POST https://staging.agentalog.com/api/guest — mr_… token for like/comment",
    "POST https://staging.agentalog.com/api/listings with a session (human) or x402 $0.10 (agent, with or without guest)",
    "GET https://staging.agentalog.com/api/listings/ID/status — poll the review (no credential; the 201 carries it as status_api)",
    "POST https://staging.agentalog.com/mcp — the same operations as MCP tools, nothing to install"
  ]
}