{
  "name": "PageAudit",
  "description": "Technical SEO auditor that ships the fix: every finding comes with its fix and the audit has a ready patch (head, robots, sitemap), with no language model. Includes llms.txt, security.txt, API catalog, function-matched well-known files, favicon response and a missing-page probe. Persistent tab workspace. The main client is an AI agent: every UI screen has an equivalent endpoint and every resource carries its own API URL.",
  "build": "359bbfd6",
  "base_url": "https://staging.pageaudit.online",
  "docs": {
    "llms": "https://staging.pageaudit.online/llms.txt",
    "llms_full": "https://staging.pageaudit.online/llms-full.txt",
    "openapi": "https://staging.pageaudit.online/openapi.json",
    "mcp": "https://staging.pageaudit.online/mcp",
    "pricing": "https://staging.pageaudit.online/api/pricing",
    "billing": "https://staging.pageaudit.online/api/billing",
    "human_ui": "https://staging.pageaudit.online/",
    "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"
      }
    ]
  },
  "conventions": {
    "format": "JSON in every `/api/*` response; an error is `{ error, detail? }` with the HTTP status.",
    "cors": "`Access-Control-Allow-Origin: *` — callable straight from the browser.",
    "links": "A resource returns `api` (or `_links`) with absolute URLs of related resources, so you navigate without building paths by hand."
  },
  "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: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing.",
    "session": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No bearer token is issued to humans.",
    "token": "Operator token in `Authorization: Bearer …` (`METRICS_TOKEN`)."
  },
  "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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/.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.pageaudit.online/apis.json",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/",
      "auth": "none",
      "summary": "Self-describing index: the whole API surface, with quota and retention policy.",
      "grupo": "Discovery",
      "retorno": {
        "name": {
          "tipo": "string",
          "desc": "Product name."
        },
        "description": {
          "tipo": "string",
          "desc": "What the product does, in one sentence."
        },
        "build": {
          "tipo": "string",
          "desc": "Deployed commit."
        },
        "base_url": {
          "tipo": "string",
          "desc": "Origin this API is serving from."
        },
        "docs": {
          "tipo": "object",
          "desc": "Links to llms.txt, llms-full.txt, openapi.json, MCP and the UI."
        },
        "conventions": {
          "tipo": "object",
          "desc": "Error format, CORS, x402 and the UI↔API parity rule."
        },
        "auth": {
          "tipo": "object",
          "desc": "Each authentication mode and how to obtain it."
        },
        "endpoints": {
          "tipo": "object[]",
          "desc": "Every endpoint with method, path, auth, absolute URL and what it returns."
        },
        "data_retention": {
          "tipo": "object",
          "desc": "What is stored from each run and what is discarded."
        },
        "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 report."
        }
      },
      "returns": "{ name, description, build, base_url, docs, conventions, auth, endpoints, data_retention, quota, mcp, quickstart }",
      "url": "https://staging.pageaudit.online/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.pageaudit.online/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.pageaudit.online/mcp",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/audit",
      "auth": "none",
      "summary": "Audits a URL and returns the full report in one call, without a token or a tab.",
      "grupo": "Audit",
      "desc": "This is the product for agents. Past the IP's daily allowance the response is **402 with `accepts[]`** — pay and repeat the same call. It also carries `sitekey` and `code`, which are the path for a human with a browser; an agent ignores those two. The free alternative: a person signs in with an account to get the trial.",
      "corpo": {
        "url": {
          "tipo": "string",
          "desc": "The page to audit, `http` or `https`.",
          "obrigatorio": true
        },
        "guest_token": {
          "tipo": "string",
          "desc": "Guest `pa_…` so the audit is tied to it and shows up in the tabs."
        },
        "cf_turnstile_response": {
          "tipo": "string",
          "desc": "Turnstile response; it is the human path, agents use x402."
        }
      },
      "body": {
        "url": "https://example.com/",
        "guest_token": "pa_… (optional, ties the audit)"
      },
      "retorno": "Audit",
      "erros": {
        "400": "Body is not JSON, or `url` missing/not http.",
        "402": null,
        "403": "Wrong Turnstile answer. A wrong captcha is not an invitation to pay.",
        "429": "Past `MAX_AUDITS_PER_HOUR` on the same IP. Wait an hour."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/audit -H 'content-type: application/json' -d '{\"url\":\"https://example.com/\"}'",
      "returns": "{ id, score, issues[{severity,code,message}], summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdErrors?,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap,discovery?}, counts{errors,warnings,info}, headers, htmlTruncated, jsonLd, jsonLdStored, truncated, fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], quota{free_per_day,price_usd}, _links{self?,patch,share?,api_index} }",
      "url": "https://staging.pageaudit.online/api/audit",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/audits/:id",
      "auth": "guest",
      "summary": "Re-reads an audit already made, in full, without re-auditing the page.",
      "grupo": "Audit",
      "desc": "Re-reading costs nothing and does not count against the allowance — the page's HTML is not kept, but the report is.",
      "params": {
        "id": {
          "desc": "Audit ID, from `Audit.id`.",
          "exemplo": "9f3c2b1d-7a4e-4c58-9b02-1f6d5e8a2c34"
        }
      },
      "retorno": "AuditGravado",
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s $ORIGIN/api/audits/AUDIT_ID -H \"X-Guest-Token: $PA\"",
      "returns": "{ audit_id, url, score, summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdErrors?,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap,discovery?}, counts{errors,warnings,info}, issues[{severity,code,message}], fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], jsonLd, headers, truncated, share_slug, created_at }",
      "url": "https://staging.pageaudit.online/api/audits/:id",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "GET",
      "path": "/api/audits/:id/patch",
      "auth": "guest",
      "summary": "The consolidated patch of an audit: the <head> block ready to paste, the files to create at the root and the templates for what only the owner can fill in — no model, only facts from the page itself.",
      "grupo": "Audit",
      "desc": "Each finding becomes a fix in one of three classes: `deterministico` (comes whole from what the page declares: final URL, title, description, OG), `molde` (a tag with a marked placeholder, like `{{TITULO}}`, and the suggested source) or `sem_patch` (a decision or infrastructure, with the instruction). Nothing is invented by a model.",
      "params": {
        "id": {
          "desc": "Audit ID, from `Audit.id`.",
          "exemplo": "9f3c2b1d-7a4e-4c58-9b02-1f6d5e8a2c34"
        }
      },
      "retorno": "Patch",
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s $ORIGIN/api/audits/AUDIT_ID/patch -H \"X-Guest-Token: $PA\"",
      "returns": "{ url, audit, head, arquivos[{code,path,conteudo}], moldes[{code,alvo,snippet,fonte,nota}], sem_patch[{code,nota}], resumo{deterministicos,moldes,sem_patch,total}, como_aplicar, _links }",
      "url": "https://staging.pageaudit.online/api/audits/:id/patch",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "GET",
      "path": "/api/tools",
      "auth": "none",
      "summary": "The micro-tools: one landing per check, all driven by the same engine as the audit.",
      "grupo": "Micro-tools",
      "retorno": {
        "tools": {
          "tipo": "Ferramenta[]",
          "desc": "Every published tool."
        },
        "_links": {
          "tipo": "object",
          "desc": "The hub in HTML and the API index."
        }
      },
      "returns": "{ tools[{slug,title,h1,description,lead,category,icon,checks,serp,sections,_links}], _links }",
      "url": "https://staging.pageaudit.online/api/tools",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/tools/:slug",
      "auth": "none",
      "summary": "Metadata and copy of one micro-tool.",
      "grupo": "Micro-tools",
      "params": {
        "slug": {
          "desc": "Tool slug, e.g. `title-tag-checker`."
        }
      },
      "retorno": "Ferramenta",
      "erros": {
        "404": "Unknown slug."
      },
      "exemplo": "curl -s $ORIGIN/api/tools/title-tag-checker",
      "returns": "{ slug, title, h1, description, lead, category, icon, checks, serp, sections, _links }",
      "url": "https://staging.pageaudit.online/api/tools/:slug",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/tools",
      "auth": "none",
      "summary": "HTML hub of the micro-tools, indexable. For JSON use `GET /api/tools`.",
      "grupo": "Micro-tools",
      "retorno": {
        "_texto": "`text/html` — the hub page, rendered on the server."
      },
      "returns": "`text/html` — the hub page, rendered on the server.",
      "url": "https://staging.pageaudit.online/tools",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/tools/:slug",
      "auth": "none",
      "summary": "HTML landing of one check, indexable. An unknown slug returns a real 404.",
      "grupo": "Micro-tools",
      "desc": "The 404 is real, not a 200 with an empty shell: mass soft-404s burn the whole domain in the index.",
      "params": {
        "slug": {
          "desc": "Tool slug, e.g. `title-tag-checker`."
        }
      },
      "retorno": {
        "_texto": "`text/html` — the tool's landing."
      },
      "erros": {
        "404": "Unknown slug — a real 404, not an empty shell."
      },
      "returns": "`text/html` — the tool's landing.",
      "url": "https://staging.pageaudit.online/tools/:slug",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/audits/:id/share",
      "auth": "guest",
      "summary": "Publishes the audit under a non-enumerable slug. Calling again returns the same slug.",
      "grupo": "Share",
      "params": {
        "id": {
          "desc": "ID of the audit to publish.",
          "exemplo": "9f3c2b1d-7a4e-4c58-9b02-1f6d5e8a2c34"
        }
      },
      "retorno": "Compartilhamento",
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s -XPOST $ORIGIN/api/audits/AUDIT_ID/share -H \"X-Guest-Token: $PA\"",
      "returns": "{ ok, shared, slug, path, badge, _links }",
      "url": "https://staging.pageaudit.online/api/audits/:id/share",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "DELETE",
      "path": "/api/audits/:id/share",
      "auth": "guest",
      "summary": "Revokes the share; the slug stops serving the report.",
      "grupo": "Share",
      "desc": "The badge keeps answering 200 with the grey `n/a` SVG — same box, so the layout of whoever pasted it in a README does not break.",
      "params": {
        "id": {
          "desc": "ID of the audit to unpublish.",
          "exemplo": "9f3c2b1d-7a4e-4c58-9b02-1f6d5e8a2c34"
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "shared": {
          "tipo": "bool",
          "desc": "Always `false` at the end of this call."
        }
      },
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s -XDELETE $ORIGIN/api/audits/AUDIT_ID/share -H \"X-Guest-Token: $PA\"",
      "returns": "{ ok, shared }",
      "url": "https://staging.pageaudit.online/api/audits/:id/share",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "GET",
      "path": "/api/shared/:slug",
      "auth": "none",
      "summary": "Shared report as JSON, without credentials — the machine twin of `/r/:slug`.",
      "grupo": "Share",
      "params": {
        "slug": {
          "desc": "Public slug of the share.",
          "exemplo": "k7m2p9r4t6v8w1y3z5b7c9d1"
        }
      },
      "retorno": "AuditGravado",
      "erros": {
        "404": "Unknown slug, or share revoked."
      },
      "exemplo": "curl -s $ORIGIN/api/shared/SLUG",
      "returns": "{ audit_id, url, score, summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdErrors?,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap,discovery?}, counts{errors,warnings,info}, issues[{severity,code,message}], fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], jsonLd, headers, truncated, share_slug, created_at }",
      "url": "https://staging.pageaudit.online/api/shared/:slug",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/r/:slug",
      "auth": "none",
      "summary": "HTML page of the shared report, indexable, canonical at `/r/:slug`.",
      "grupo": "Share",
      "desc": "A public report is content: indexable, with its own canonical. Revoked or unknown slugs answer 404 (that one is `noindex`). The JSON twin is `/api/shared/:slug`.",
      "params": {
        "slug": {
          "desc": "Public slug of the share.",
          "exemplo": "k7m2p9r4t6v8w1y3z5b7c9d1"
        }
      },
      "retorno": {
        "_texto": "`text/html` — the rendered report, with `rel=canonical`."
      },
      "erros": {
        "404": "Unknown or revoked slug."
      },
      "returns": "`text/html` — the rendered report, with `rel=canonical`.",
      "url": "https://staging.pageaudit.online/r/:slug",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/badge/:slug",
      "auth": "none",
      "summary": "Metadata of the score badge, including the markdown ready for the README.",
      "grupo": "Share",
      "params": {
        "slug": {
          "desc": "Public slug of the share.",
          "exemplo": "k7m2p9r4t6v8w1y3z5b7c9d1"
        }
      },
      "retorno": "Badge",
      "erros": {
        "404": "Unknown slug. Revoked is different: it returns 200 with `available: false`."
      },
      "exemplo": "curl -s $ORIGIN/api/badge/SLUG",
      "returns": "{ slug, score, label, available, markdown, _links }",
      "url": "https://staging.pageaudit.online/api/badge/:slug",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/badge/:slug.svg",
      "auth": "none",
      "summary": "SVG score badge, to paste in the README of the audited project.",
      "grupo": "Share",
      "desc": "A revoked share returns **200** with the grey `n/a` SVG — the same box, so the README of whoever pasted it does not end up with a broken image.",
      "params": {
        "slug": {
          "desc": "Public slug, with the `.svg` extension in the path.",
          "exemplo": "k7m2p9r4t6v8w1y3z5b7c9d1"
        }
      },
      "retorno": {
        "_texto": "`image/svg+xml` — the badge, coloured by the score or grey `n/a` if revoked."
      },
      "erros": {
        "404": "Malformed slug."
      },
      "returns": "`image/svg+xml` — the badge, coloured by the score or grey `n/a` if revoked.",
      "url": "https://staging.pageaudit.online/badge/:slug.svg",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/embed",
      "auth": "none",
      "summary": "The embeddable widget's contract: what you can configure and the snippet to paste.",
      "grupo": "Embed",
      "desc": "One script tag puts the audit form on your own site, with your name and colour, and no account or key. Send the same query you would send to `/embed` and the answer comes back with `snippet` already assembled. The widget never asks the visitor for an e-mail.",
      "query": {
        "brand": {
          "desc": "Your site's name, shown above the form (up to 40 characters)."
        },
        "color": {
          "desc": "Accent colour in hex (`#0a7` or `#00aa77`); anything else falls back to ours."
        },
        "theme": {
          "desc": "`auto` (follows the visitor), `light` or `dark`."
        },
        "url": {
          "desc": "Optional http(s) URL to pre-fill in the field."
        }
      },
      "retorno": {
        "config": {
          "tipo": "object",
          "desc": "Each option, its type and what it does."
        },
        "current": {
          "tipo": "object",
          "desc": "The configuration read from this call's query."
        },
        "snippet": {
          "tipo": "string",
          "desc": "The `<script>` (plus a `<noscript>` link) ready to paste."
        },
        "limits": {
          "tipo": "object",
          "desc": "The allowance the widget runs under, and the lead capture it does not do."
        }
      },
      "exemplo": "curl -s \"$ORIGIN/api/embed?brand=Acme&color=%2300aa77\"",
      "returns": "{ config, current, snippet, limits }",
      "url": "https://staging.pageaudit.online/api/embed",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/embed.js",
      "auth": "none",
      "summary": "The loader you paste: it creates the widget's iframe and keeps it the right height.",
      "grupo": "Embed",
      "desc": "Configuration travels in `data-brand`, `data-color`, `data-theme` and `data-url` on the script tag itself. Nothing else of ours touches the host page: the widget lives inside the iframe, so neither the site's CSS reaches it nor our code reaches the site's DOM.",
      "retorno": {
        "_texto": "`application/javascript` — the loader, cached for an hour."
      },
      "returns": "`application/javascript` — the loader, cached for an hour.",
      "url": "https://staging.pageaudit.online/embed.js",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/embed",
      "auth": "none",
      "summary": "The widget page itself, made to be framed (`frame-ancestors *`) and not indexed.",
      "grupo": "Embed",
      "desc": "Open it directly to preview a configuration before pasting the snippet. It calls `POST /api/audit` like any visitor would, so the free daily allowance per network applies.",
      "retorno": {
        "_texto": "`text/html` — the widget, self-contained, with no third-party resource."
      },
      "returns": "`text/html` — the widget, self-contained, with no third-party resource.",
      "url": "https://staging.pageaudit.online/embed",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "POST",
      "path": "/api/guest",
      "auth": "none",
      "summary": "Creates a guest `pa_…` — it is what gives access to the tab workspace without an account.",
      "grupo": "Identity",
      "desc": "Keep the token: it is the identity of the tabs and of the audits tied to them.",
      "retorno": {
        "token": {
          "tipo": "string",
          "desc": "The guest, prefix `pa_`. Send it in `X-Guest-Token`, as Bearer or in `?guest_token=`."
        }
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/guest",
      "returns": "{ token }",
      "url": "https://staging.pageaudit.online/api/guest",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/tabs",
      "auth": "guest",
      "summary": "The owner's whole workspace, with the active tab's result already rehydrated.",
      "grupo": "Tabs",
      "desc": "One call draws the whole screen: tabs, the focused tab, its last report, remaining allowance and prices.",
      "retorno": "Workspace",
      "erros": [
        401
      ],
      "exemplo": "curl -s $ORIGIN/api/tabs -H \"X-Guest-Token: $PA\"",
      "returns": "{ tabs[{id,url,alias,active,audit_id,score,monitor,monitor_email,monitor_checked_at,created_at}], active_id, active_result{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at}, limit, owner, gate{ip,now,configured,free_allowance,free_remaining,verified_until,needs_verification,sitekey}, billing }",
      "url": "https://staging.pageaudit.online/api/tabs",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "POST",
      "path": "/api/tabs",
      "auth": "guest",
      "summary": "Opens a tab for the URL, or focuses the one that already exists for it.",
      "grupo": "Tabs",
      "desc": "Past the free tab allowance it answers 402 with `accepts[]`: pay and repeat.",
      "corpo": {
        "url": {
          "tipo": "string",
          "desc": "The URL the tab will follow.",
          "obrigatorio": true
        },
        "alias": {
          "tipo": "string",
          "desc": "Label to recognise the tab in the list."
        }
      },
      "body": {
        "url": "https://example.com/",
        "alias": "optional label"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "tab": {
          "tipo": "Aba",
          "desc": "The opened tab (or the one that already existed for that URL)."
        }
      },
      "erros": {
        "400": "`url` missing or not http.",
        "401": null,
        "402": null
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/tabs -H \"X-Guest-Token: $PA\" -H 'content-type: application/json' -d '{\"url\":\"https://example.com/\"}'",
      "returns": "{ ok, tab{id,url,alias,active,audit_id,score,monitor,monitor_email,monitor_checked_at,created_at} }",
      "url": "https://staging.pageaudit.online/api/tabs",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "GET",
      "path": "/api/tabs/:id",
      "auth": "guest",
      "summary": "One tab with the full report of its last run.",
      "grupo": "Tabs",
      "params": {
        "id": {
          "desc": "Tab ID, from `Aba.id`.",
          "exemplo": "tab_9f3c2b1d7a4e58b0c2d4"
        }
      },
      "retorno": {
        "tab": {
          "tipo": "Aba",
          "desc": "The requested tab."
        },
        "result": {
          "tipo": "AuditGravado",
          "desc": "The report of the last run; `null` if the tab never ran.",
          "nulo": true
        }
      },
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s $ORIGIN/api/tabs/TAB_ID -H \"X-Guest-Token: $PA\"",
      "returns": "{ tab{id,url,alias,active,audit_id,score,monitor,monitor_email,monitor_checked_at,created_at}, result{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at} }",
      "url": "https://staging.pageaudit.online/api/tabs/:id",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "PATCH",
      "path": "/api/tabs/:id",
      "auth": "guest",
      "summary": "Renames the tab, puts it in focus or turns the daily watch on and off.",
      "grupo": "Tabs",
      "desc": "With `monitor: true` the page is re-audited once a day and an e-mail goes out when the score drops or a new error/warning appears — never on an improvement. Watching needs an account (the alert has to reach someone) and each account watches a limited number of pages.",
      "params": {
        "id": {
          "desc": "ID of the tab to change.",
          "exemplo": "tab_9f3c2b1d7a4e58b0c2d4"
        }
      },
      "corpo": {
        "alias": {
          "tipo": "string",
          "desc": "New label of the tab."
        },
        "active": {
          "tipo": "bool",
          "desc": "`true` focuses this tab (and unfocuses the other)."
        },
        "monitor": {
          "tipo": "bool",
          "desc": "`true` watches the page daily; `false` stops watching it."
        },
        "monitor_email": {
          "tipo": "string",
          "desc": "Where the alert goes. Empty or `null` uses the account's e-mail."
        }
      },
      "body": {
        "alias": "new label",
        "active": true,
        "monitor": true
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "tab": {
          "tipo": "Aba",
          "desc": "The tab with the change applied."
        }
      },
      "erros": {
        "400": "No changeable field in the body, or `monitor_email` is not an e-mail.",
        "401": null,
        "403": "Watching needs an account: a guest token has no e-mail to be warned at (`account_required`).",
        "404": null,
        "409": "The account already watches the maximum number of pages (`monitor_limit`)."
      },
      "exemplo": "curl -s -XPATCH $ORIGIN/api/tabs/TAB_ID -H \"X-Guest-Token: $PA\" -H 'content-type: application/json' -d '{\"active\":true}'",
      "returns": "{ ok, tab{id,url,alias,active,audit_id,score,monitor,monitor_email,monitor_checked_at,created_at} }",
      "url": "https://staging.pageaudit.online/api/tabs/:id",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "DELETE",
      "path": "/api/tabs/:id",
      "auth": "guest",
      "summary": "Closes the tab. Its audit history keeps existing.",
      "grupo": "Tabs",
      "params": {
        "id": {
          "desc": "ID of the tab to close.",
          "exemplo": "tab_9f3c2b1d7a4e58b0c2d4"
        }
      },
      "retorno": "Ok",
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s -XDELETE $ORIGIN/api/tabs/TAB_ID -H \"X-Guest-Token: $PA\"",
      "returns": "{ ok }",
      "url": "https://staging.pageaudit.online/api/tabs/:id",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "POST",
      "path": "/api/tabs/:id/run",
      "auth": "guest",
      "summary": "Re-audits the tab's URL and stores a new report.",
      "grupo": "Tabs",
      "desc": "Consumes the same daily allowance as `POST /api/audit` — past it, 402 with `accepts[]`.",
      "params": {
        "id": {
          "desc": "ID of the tab to re-audit.",
          "exemplo": "tab_9f3c2b1d7a4e58b0c2d4"
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true`."
        },
        "tab": {
          "tipo": "Aba",
          "desc": "The tab with the new run's score."
        },
        "gate": {
          "tipo": "Gate",
          "desc": "How much of the allowance is left after this run."
        },
        "result": {
          "tipo": "AuditGravado",
          "desc": "The report just stored."
        }
      },
      "erros": [
        401,
        402,
        404
      ],
      "exemplo": "curl -s -XPOST $ORIGIN/api/tabs/TAB_ID/run -H \"X-Guest-Token: $PA\"",
      "returns": "{ ok, tab{id,url,alias,active,audit_id,score,monitor,monitor_email,monitor_checked_at,created_at}, gate{ip,now,configured,free_allowance,free_remaining,verified_until,needs_verification,sitekey}, result{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at} }",
      "url": "https://staging.pageaudit.online/api/tabs/:id/run",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "GET",
      "path": "/api/tabs/:id/history",
      "auth": "guest",
      "summary": "Previous runs of that tab and what changed between each one and the one before it.",
      "grupo": "Tabs",
      "desc": "Every run has always been kept; this is where you read the series. Each entry carries the score, the counts and a `change` with the point delta and the findings that appeared (`broke`) or disappeared (`fixed`) since the previous run — compared by finding code, never by message. Runs older than the watch feature are matched by URL.",
      "params": {
        "id": {
          "desc": "ID of the tab whose runs you want.",
          "exemplo": "tab_9f3c2b1d7a4e58b0c2d4"
        }
      },
      "query": {
        "limit": {
          "desc": "How many runs to bring, newest first. Default 20, maximum 100."
        }
      },
      "retorno": {
        "tab": {
          "tipo": "Aba",
          "desc": "The tab the runs belong to."
        },
        "runs": {
          "tipo": "RunHistorico[]",
          "desc": "Runs from newest to oldest."
        },
        "limit": {
          "tipo": "int",
          "desc": "The limit actually applied."
        }
      },
      "erros": [
        401,
        404
      ],
      "exemplo": "curl -s \"$ORIGIN/api/tabs/TAB_ID/history?limit=10\" -H \"X-Guest-Token: $PA\"",
      "returns": "{ tab{id,url,alias,active,audit_id,score,monitor,monitor_email,monitor_checked_at,created_at}, runs[{audit_id,score,counts,created_at,change,shared,api}], limit }",
      "url": "https://staging.pageaudit.online/api/tabs/:id/history",
      "auth_detail": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. Only a token this site issued is accepted. A signed-in account (cookie) also works and takes precedence; after the claim the token owns nothing."
    },
    {
      "method": "GET",
      "path": "/api/gate",
      "auth": "none",
      "summary": "How many free audits remain for this IP and whether Turnstile is about to be required.",
      "grupo": "Tabs",
      "desc": "Check before spending a call: it is the number IN FORCE, not the allowance in the documentation.",
      "retorno": "Gate",
      "returns": "{ ip, now, configured, free_allowance, free_remaining, verified_until, needs_verification, sitekey }",
      "url": "https://staging.pageaudit.online/api/gate",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/billing",
      "auth": "none",
      "summary": "Tab allowance, prices, full x402 configuration and the state of the trial.",
      "grupo": "Billing",
      "retorno": "Billing",
      "exemplo": "curl -s $ORIGIN/api/billing -H \"X-Guest-Token: $PA\"",
      "returns": "{ provider, mode, network, chain_id, pay_to, homolog, dev, dev_gate, gratis?, facilitator, asset, asset_address, faucet, wallets, product, free_max_tabs, prices{extra_tab_usd,contact_agent_usd}, usage{tabs,free_slots_left}, trial{days,active,days_left?,ends_at} }",
      "url": "https://staging.pageaudit.online/api/billing",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/me",
      "auth": "session",
      "summary": "The session's account, its last 50 audits and the state of the trial.",
      "desc": "The account is the global account you sign in to at `/conta/global`, the same in every product; `user.id` is its id, which owns the tabs and audits here. There is no activation step.",
      "grupo": "Account",
      "retorno": {
        "user": {
          "tipo": "Conta",
          "desc": "The person who owns the session."
        },
        "profile": {
          "tipo": "object",
          "desc": "Global profile: `name`, `locale`, `timeZone`, `theme`, `revision`."
        },
        "audits": {
          "tipo": "AuditGravado[]",
          "desc": "The account's 50 most recent audits."
        },
        "trial": {
          "tipo": "Trial",
          "desc": "The account's trial: how many days, whether active and when it ends."
        }
      },
      "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, audits[{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at}], trial{days,active,days_left?,ends_at} }",
      "url": "https://staging.pageaudit.online/api/me",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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.pageaudit.online/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.pageaudit.online/api/account/profile",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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.pageaudit.online/api/account/avatar",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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.pageaudit.online/api/auth/logout",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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.pageaudit.online/api/account/keys",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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.pageaudit.online/api/account/keys/create",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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.pageaudit.online/api/account/keys/revoke",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. 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: tabs and audits.",
      "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": true,
          "desc": "Guest `pa_…` of this browser."
        }
      },
      "body": {
        "guest_token": "pa_…"
      },
      "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: JSON.stringify({guest_token: localStorage.getItem(\"pageaudit_guest\")})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok, claimed }",
      "url": "https://staging.pageaudit.online/api/auth/claim",
      "auth_detail": "Global account: HttpOnly cookie `__Host-mm-auth`, set when you sign in on this site's `/conta/global` page. An ended session answers 401 `session_ended` (it never falls back to the guest). Writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No bearer token is issued to humans."
    },
    {
      "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": "Without a captcha in the body the request is treated as an agent: 402 until paid. 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": "…",
        "cf_turnstile_response": "(human)"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Always `true` when the message was accepted."
        },
        "path": {
          "tipo": "string",
          "desc": "Which path it came through: human with captcha or paid agent."
        }
      },
      "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, path }",
      "url": "https://staging.pageaudit.online/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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/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.pageaudit.online/api/partners",
      "auth_detail": "Public, no credential."
    },
    {
      "method": "GET",
      "path": "/api/metrics",
      "auth": "none",
      "summary": "Metrics of the last 7 days and the most frequent findings across audits. 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?, achados }",
      "url": "https://staging.pageaudit.online/api/metrics",
      "auth_detail": "Public, no credential."
    },
    {
      "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.pageaudit.online/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.pageaudit.online/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."
    },
    {
      "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.pageaudit.online/api/pricing",
      "auth_detail": "Public, no credential."
    }
  ],
  "data_retention": {
    "stored": "Each run writes one row in `audits` with the whole result: summary (including the redirect chain, the origin's robots.txt/sitemap, alt, links, word count, hreflang and legacy markup, discovery checks with evidence and references), issues, counts, the raw JSON-LD and every response header.",
    "not_stored": [
      "The page's HTML — downloaded up to 2 MB, analysed and discarded. Re-reading requires a new run.",
      "The target's `Set-Cookie`, removed on purpose: it is a third party's credential and no check uses it.",
      "Discovery-file bodies: only bounded observations are stored; their text is never executed and their links are not crawled."
    ],
    "truncation": "Nothing disappears silently. Size cuts show up in `truncated[]` (`jsonld_size`, `jsonld_nodes_over_50`, `result_size`) and `summary.jsonLdBlocks` / `summary.jsonLdDropped` say how many blocks existed and how many were left out."
  },
  "quota": {
    "free": [
      {
        "o_que": "audit (`POST /api/audit`)",
        "limite": "10 per IP",
        "janela": "day"
      },
      {
        "o_que": "audit — rate ceiling",
        "limite": "300 per IP",
        "janela": "hour"
      },
      {
        "o_que": "workspace tabs",
        "limite": "20 per owner",
        "janela": null
      }
    ],
    "paid": [
      {
        "o_que": "audit beyond the daily allowance",
        "price_usd": 0.02
      },
      {
        "o_que": "tab beyond the allowance",
        "price_usd": 0.05
      },
      {
        "o_que": "agent contact",
        "price_usd": 0.1
      }
    ],
    "how_to_pay": "Past the allowance → **402** with `accepts[]` (x402, USDC on Base). Pay and repeat the same call with `X-PAYMENT`. A human in a browser solves Turnstile and does not pay. Free alternative: a person signs in with an account (trial below).",
    "live": "https://staging.pageaudit.online/api/billing",
    "free_now": [
      "audit",
      "extra_tab"
    ],
    "trial": {
      "days": 90,
      "how": "Sign in with an account at /conta/global (browser: e-mail code or link, password or passkey) → 90 days without paywall, counted from the account's first use of PageAudit"
    }
  },
  "mcp": {
    "endpoint": "https://staging.pageaudit.online/mcp",
    "transport": "streamable-http",
    "tools": 18,
    "note": "Plugs straight into the MCP client; nothing to install. Tools = the operations below."
  },
  "quickstart": [
    "curl -s https://staging.pageaudit.online/api/audit -H 'Content-Type: application/json' -d '{\"url\":\"https://example.com/\"}'",
    "TOKEN=$(curl -s -XPOST https://staging.pageaudit.online/api/guest | jq -r .token)",
    "curl -s https://staging.pageaudit.online/api/tabs -H \"X-Guest-Token: $TOKEN\""
  ]
}