{ "openapi": "3.1.0", "info": { "title": "PageAudit", "version": "f5ac3ca0", "description": "Technical SEO auditor that ships the fix. Main client: AI agents. Browsable index at GET /api/." }, "servers": [ { "url": "https://pageaudit.online" } ], "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Guest token (`POST /api/guest`) in `X-Guest-Token: pa_…`, `Authorization: Bearer pa_…` or `?guest_token=pa_…`. A user session (`sess_…`) also works and takes precedence." } }, "schemas": { "Audit": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the stored audit; `null` when the database was unavailable.", "nullable": true }, "score": { "type": "integer", "description": "Score from 0 to 100, computed from the findings below." }, "issues": { "type": "array", "items": { "$ref": "#/components/schemas/Achado" }, "description": "Everything found, from most to least severe." }, "summary": { "allOf": [ { "$ref": "#/components/schemas/ResumoPagina" } ], "description": "What the page declares: title, meta, canonical, OG, headings, links…" }, "counts": { "allOf": [ { "$ref": "#/components/schemas/ContagemAchados" } ], "description": "How many findings of each severity." }, "headers": { "type": "object", "description": "Every header of the target's response. `Set-Cookie` is removed on purpose: it is a third party's credential." }, "htmlTruncated": { "type": "boolean", "description": "`true` when the page passed 2 MB and was read only that far." }, "jsonLd": { "type": "array", "items": { "type": "object" }, "description": "The raw JSON-LD blocks, as they were on the page." }, "jsonLdStored": { "type": "integer", "description": "How many blocks survived the size cap — compare with `summary.jsonLdBlocks`." }, "truncated": { "type": "array", "items": { "type": "string" }, "description": "What was cut and why: `jsonld_size`, `jsonld_nodes_over_50`, `result_size`. Empty means nothing cut." }, "fixes": { "type": "array", "items": { "$ref": "#/components/schemas/Correcao" }, "description": "The ready fix of each finding, without a model — paste, fill in or decide. The consolidated one is at `_links.patch`." }, "quota": { "allOf": [ { "$ref": "#/components/schemas/CotaAudit" } ], "description": "How much is still free and what it costs past that." }, "_links": { "allOf": [ { "$ref": "#/components/schemas/LinksAudit" } ], "description": "This audit, the patch, the share and the API index." } }, "required": [ "id", "score", "issues", "summary", "counts", "headers", "htmlTruncated", "jsonLd", "jsonLdStored", "truncated", "fixes", "quota", "_links" ], "description": "The report of one audit: score, findings and everything observed on the page." }, "Achado": { "type": "object", "properties": { "severity": { "type": "string", "description": "Severity of the finding." }, "code": { "type": "string", "description": "Stable check code, e.g. `title_missing`. It is what you filter by." }, "message": { "type": "string", "description": "The finding in one sentence, ready to show a person." } }, "required": [ "severity", "code", "message" ], "description": "A problem (or a pass) found on the page." }, "ResumoPagina": { "type": "object", "properties": { "finalUrl": { "type": "string", "description": "URL after following every redirect." }, "status": { "type": "integer", "description": "Final HTTP status of the target." }, "contentType": { "type": "string", "description": "Content-Type of the final response.", "nullable": true }, "title": { "type": "string", "description": "Content of ``.", "nullable": true }, "metaDescription": { "type": "string", "description": "Content of `<meta name=description>`.", "nullable": true }, "canonical": { "type": "string", "description": "Canonical URL declared by the page.", "nullable": true }, "robots": { "type": "string", "description": "Content of `<meta name=robots>`.", "nullable": true }, "viewport": { "type": "string", "description": "Content of `<meta name=viewport>`.", "nullable": true }, "charset": { "type": "string", "description": "Declared encoding.", "nullable": true }, "lang": { "type": "string", "description": "Language declared in `<html lang>`.", "nullable": true }, "favicon": { "type": "string", "description": "URL of the favicon found.", "nullable": true }, "faviconSource": { "type": "string", "description": "How the favicon was found: declared or by the default path.", "nullable": true }, "h1s": { "type": "array", "items": { "type": "string" }, "description": "Every `<h1>` on the page, in order." }, "openGraph": { "type": "object", "description": "The `og:*` tags found, key by key." }, "twitter": { "type": "object", "description": "The `twitter:*` tags found." }, "jsonLdCount": { "type": "integer", "description": "How many JSON-LD nodes the page had." }, "jsonLdBlocks": { "type": "integer", "description": "How many `<script type=application/ld+json>` blocks existed." }, "jsonLdDropped": { "type": "boolean", "description": "`true` when nodes were dropped for passing the cap." }, "jsonLdTypes": { "type": "array", "items": { "type": "string" }, "description": "The `@type`s found, e.g. `Organization`, `WebSite`." }, "images": { "type": "object", "description": "Image count and how many have no `alt`." }, "links": { "type": "object", "description": "Count of internal, external and text-less links." }, "words": { "type": "integer", "description": "Words in the visible content." }, "hreflang": { "type": "array", "items": { "type": "object" }, "description": "The declared language alternates." }, "legacy": { "type": "object", "description": "Old markup still present (e.g. `<font>`, layout tables)." }, "redirects": { "type": "array", "items": { "type": "object" }, "description": "The redirect chain followed to the final URL." }, "robotsTxt": { "type": "object", "description": "What the origin's `robots.txt` says about this URL." }, "sitemap": { "type": "object", "description": "Whether the URL appears in the sitemap the origin declares." } }, "required": [ "finalUrl", "status", "contentType", "title", "metaDescription", "canonical", "robots", "viewport", "charset", "lang", "favicon", "faviconSource", "h1s", "openGraph", "twitter", "jsonLdCount", "jsonLdBlocks", "jsonLdDropped", "jsonLdTypes", "images", "links", "words", "hreflang", "legacy", "redirects", "robotsTxt", "sitemap" ], "description": "Everything the page declares about itself. It is the most consulted object of the API." }, "ContagemAchados": { "type": "object", "properties": { "errors": { "type": "integer", "description": "Serious findings." }, "warnings": { "type": "integer", "description": "Findings that deserve attention." }, "info": { "type": "integer", "description": "Observations without severity." } }, "required": [ "errors", "warnings", "info" ], "description": "How many findings of each severity — the summary that fits in a badge." }, "Correcao": { "type": "object", "properties": { "code": { "type": "string", "description": "The same `code` as the finding (`Achado.code`)." }, "severity": { "type": "string", "description": "Severity of the source finding." }, "classe": { "type": "string", "description": "`deterministico` comes whole from the page; `molde` has a `{{…}}` placeholder; `sem_patch` is an instruction." }, "alvo": { "type": "string", "description": "Where to apply: `head`, `corpo`, `img`, `arquivo` or `pagina` (instruction)." }, "snippet": { "type": "string", "description": "The ready tag (or with a placeholder). `null` for files and for `sem_patch`.", "nullable": true }, "arquivo": { "type": "object", "description": "`path` and `conteudo` when the fix is a file at the host root.", "nullable": true }, "fonte": { "type": "string", "description": "Where the value came from, or what the page already had (for the template or to check the cut).", "nullable": true }, "nota": { "type": "string", "description": "How to apply, or what to decide.", "nullable": true } }, "required": [ "code", "severity", "classe", "alvo", "snippet", "arquivo", "fonte", "nota" ], "description": "The ready fix of one finding. `classe` says whether it is to paste, to fill in or to decide." }, "CotaAudit": { "type": "object", "properties": { "free_per_day": { "type": "integer", "description": "Free audits per IP per day." }, "price_usd": { "type": "number", "description": "Price of an audit beyond the allowance, in USD." } }, "required": [ "free_per_day", "price_usd" ], "description": "How much is still free and what it costs past that." }, "LinksAudit": { "type": "object", "properties": { "self": { "type": "string", "description": "This audit, to re-read without re-auditing." }, "patch": { "type": "string", "description": "`GET /api/audits/:id/patch` — the consolidated patch of this audit.", "nullable": true }, "share": { "type": "string", "description": "Where to publish this audit under a public slug." }, "api_index": { "type": "string", "description": "Self-describing API index." } }, "required": [ "patch", "api_index" ], "description": "Addresses of the audit just created. Without a stored `id`, only `api_index` comes." }, "AuditGravado": { "type": "object", "properties": { "audit_id": { "type": "string", "description": "ID of the audit." }, "url": { "type": "string", "description": "Final audited URL, after following the redirects." }, "score": { "type": "integer", "description": "Score from 0 to 100." }, "summary": { "allOf": [ { "$ref": "#/components/schemas/ResumoPagina" } ], "description": "What the page declared at the time of the run.", "nullable": true }, "counts": { "allOf": [ { "$ref": "#/components/schemas/ContagemAchados" } ], "description": "How many findings of each severity." }, "issues": { "type": "array", "items": { "$ref": "#/components/schemas/Achado" }, "description": "Everything found in that run." }, "fixes": { "type": "array", "items": { "$ref": "#/components/schemas/Correcao" }, "description": "The ready fix of each finding; an audit stored before this existed gets the computation on read." }, "jsonLd": { "type": "array", "items": { "type": "object" }, "description": "The raw JSON-LD blocks stored." }, "headers": { "type": "object", "description": "Headers of the target's response, as they were in the run." }, "truncated": { "type": "array", "items": { "type": "string" }, "description": "What was cut by size when storing." }, "share_slug": { "type": "string", "description": "Public slug, if this audit was shared.", "nullable": true }, "created_at": { "type": "string", "description": "When the run happened (UTC)." } }, "required": [ "audit_id", "url", "score", "summary", "counts", "issues", "fixes", "jsonLd", "headers", "truncated", "share_slug", "created_at" ], "description": "The same report re-read from the database. It has no `quota` and no `_links` (it is a read, not a run) and gains the date and the share slug." }, "Patch": { "type": "object", "properties": { "url": { "type": "string", "description": "Final audited URL.", "nullable": true }, "audit": { "type": "string", "description": "Absolute link of the source audit.", "nullable": true }, "head": { "type": "string", "description": "The deterministic tags, one per line, in <head> order (charset first). Empty when there are none." }, "arquivos": { "type": "array", "items": { "$ref": "#/components/schemas/ArquivoPatch" }, "description": "Files to create at the host root." }, "moldes": { "type": "array", "items": { "$ref": "#/components/schemas/MoldePatch" }, "description": "What only the owner can fill in." }, "sem_patch": { "type": "array", "items": { "$ref": "#/components/schemas/SemPatch" }, "description": "What is a decision or infrastructure." }, "resumo": { "allOf": [ { "$ref": "#/components/schemas/ResumoPatch" } ], "description": "Count per class." }, "como_aplicar": { "type": "string", "description": "One-sentence instruction." }, "_links": { "type": "object", "description": "`api_index`." } }, "required": [ "url", "audit", "head", "arquivos", "moldes", "sem_patch", "resumo", "como_aplicar", "_links" ], "description": "The consolidated patch of an audit, ready for the agent that builds the site to apply." }, "ArquivoPatch": { "type": "object", "properties": { "code": { "type": "string", "description": "Finding that originated it (`robots_txt_missing`, `sitemap_missing`)." }, "path": { "type": "string", "description": "Absolute path on the host, e.g. `/robots.txt`." }, "conteudo": { "type": "string", "description": "Full content of the file." } }, "required": [ "code", "path", "conteudo" ], "description": "A file to create at the host root." }, "MoldePatch": { "type": "object", "properties": { "code": { "type": "string", "description": "Source finding." }, "alvo": { "type": "string", "description": "`head`, `corpo` or `img`." }, "snippet": { "type": "string", "description": "The tag with `{{PLACEHOLDER}}`." }, "fonte": { "type": "string", "description": "Suggestion taken from the page itself (H1, og:description…), if any.", "nullable": true }, "nota": { "type": "string", "description": "What to fill in and the limit." } }, "required": [ "code", "alvo", "snippet", "fonte", "nota" ], "description": "A tag with a marked placeholder: content missing that only the owner knows." }, "SemPatch": { "type": "object", "properties": { "code": { "type": "string", "description": "Source finding." }, "nota": { "type": "string", "description": "What to check or decide." } }, "required": [ "code", "nota" ], "description": "Finding without an automatic fix: it is a decision or infrastructure." }, "ResumoPatch": { "type": "object", "properties": { "deterministicos": { "type": "integer", "description": "Ready to paste (head + files)." }, "moldes": { "type": "integer", "description": "With a placeholder." }, "sem_patch": { "type": "integer", "description": "Instruction only." }, "total": { "type": "integer", "description": "Findings considered." } }, "required": [ "deterministicos", "moldes", "sem_patch", "total" ], "description": "How many fixes of each class." }, "Ferramenta": { "type": "object", "properties": { "slug": { "type": "string", "description": "Identifier in the URL, e.g. `title-tag-checker`." }, "title": { "type": "string", "description": "Page title, used in `<title>`." }, "h1": { "type": "string", "description": "The landing's H1." }, "description": { "type": "string", "description": "Meta description of the landing." }, "lead": { "type": "string", "description": "Opening paragraph." }, "category": { "type": "string", "description": "Grouping of the tool in the hub." }, "icon": { "type": "string", "description": "Name of the icon used in the card." }, "checks": { "type": "array", "items": { "type": "string" }, "description": "Finding codes this tool highlights — they are the `Achado.code`s." }, "serp": { "type": "object", "description": "How the result looks in the search preview." }, "sections": { "type": "array", "items": { "type": "object" }, "description": "Content blocks of the landing." }, "_links": { "type": "object", "description": "This tool in JSON and in HTML." } }, "required": [ "slug", "title", "h1", "description", "lead", "category", "icon", "checks", "serp", "sections", "_links" ], "description": "A micro-tool: the landing of one isolated check, with the same engine as the full audit." }, "Compartilhamento": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "shared": { "type": "boolean", "description": "Whether the audit is published at the end of the call." }, "slug": { "type": "string", "description": "Public, non-enumerable slug." }, "path": { "type": "string", "description": "Path of the report's HTML page." }, "badge": { "type": "string", "description": "Path of the score badge SVG." }, "_links": { "type": "object", "description": "Report, JSON and badge, as absolute URLs." } }, "required": [ "ok", "shared", "slug", "path", "badge", "_links" ], "description": "The result of publishing an audit under a non-enumerable slug." }, "Badge": { "type": "object", "properties": { "slug": { "type": "string", "description": "Slug of the shared report." }, "score": { "type": "integer", "description": "Score shown in the badge.", "nullable": true }, "label": { "type": "string", "description": "Text on the left of the badge." }, "available": { "type": "boolean", "description": "`false` when the share was revoked — the SVG turns grey `n/a`." }, "markdown": { "type": "string", "description": "The markdown line ready to paste in the README." }, "_links": { "type": "object", "description": "The SVG and the report." } }, "required": [ "slug", "score", "label", "available", "markdown", "_links" ], "description": "The score badge metadata, to build the README markdown." }, "Workspace": { "type": "object", "properties": { "tabs": { "type": "array", "items": { "$ref": "#/components/schemas/Aba" }, "description": "Every tab of the owner." }, "active_id": { "type": "string", "description": "Which tab is in focus.", "nullable": true }, "active_result": { "allOf": [ { "$ref": "#/components/schemas/AuditGravado" } ], "description": "The last result of the active tab, so a second call is not needed.", "nullable": true }, "limit": { "type": "integer", "description": "How many tabs fit before paying." }, "owner": { "type": "string", "description": "Identifier of this workspace's owner." }, "gate": { "allOf": [ { "$ref": "#/components/schemas/Gate" } ], "description": "How much of the IP's free allowance remains." }, "billing": { "type": "object", "description": "Prices and usage, the same `GET /api/billing` returns." } }, "required": [ "tabs", "active_id", "active_result", "limit", "owner", "gate", "billing" ], "description": "The owner's whole workspace, with the active tab's result already rehydrated — one call to draw the screen." }, "Aba": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the tab." }, "url": { "type": "string", "description": "URL the tab follows." }, "alias": { "type": "string", "description": "Label the person gave the tab.", "nullable": true }, "active": { "type": "boolean", "description": "Whether it is the focused tab in the workspace." }, "audit_id": { "type": "string", "description": "Audit of this tab's last run.", "nullable": true }, "score": { "type": "integer", "description": "Score of the last run.", "nullable": true }, "created_at": { "type": "string", "description": "When the tab was opened (UTC)." } }, "required": [ "id", "url", "alias", "active", "audit_id", "score", "created_at" ], "description": "A workspace tab: one followed URL, with the last result kept." }, "Gate": { "type": "object", "properties": { "ip": { "type": "string", "description": "IP seen by the edge, already masked." }, "now": { "type": "integer", "description": "Time of the query, in epoch." }, "configured": { "type": "boolean", "description": "Whether Turnstile is configured in this environment." }, "free_allowance": { "type": "integer", "description": "Free audits per day." }, "free_remaining": { "type": "integer", "description": "How many remain today for this IP." }, "verified_until": { "type": "integer", "description": "Until when the verification already done is valid.", "nullable": true }, "needs_verification": { "type": "boolean", "description": "`true` when the next call will ask for Turnstile (human) or 402 (agent)." }, "sitekey": { "type": "string", "description": "Turnstile sitekey, for the browser to build the challenge.", "nullable": true } }, "required": [ "ip", "now", "configured", "free_allowance", "free_remaining", "verified_until", "needs_verification", "sitekey" ], "description": "How much of the daily allowance still exists for this IP, and whether Turnstile is already required." }, "Ok": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true` — failure comes as a 4xx/5xx status, not as `ok:false`." } }, "required": [ "ok" ], "description": "Write confirmation with no body of its own to return." }, "Billing": { "type": "object", "properties": { "provider": { "type": "string", "description": "Always `x402` — the only billing protocol accepted." }, "mode": { "type": "string", "description": "Seller mode: `live` charges for real, `dev` lets calls through unpaid." }, "network": { "type": "string", "description": "USDC network: `base` in production, `base-sepolia` in staging." }, "chain_id": { "type": "integer", "description": "EVM chain ID of the network above, so the wallet signs on the right chain." }, "pay_to": { "type": "string", "description": "Address that receives the payment.", "nullable": true }, "homolog": { "type": "boolean", "description": "Staging seam on: the loop can be closed without spending USDC." }, "dev": { "type": "boolean", "description": "Development mode: the 402 is simulated." }, "dev_gate": { "type": "string", "description": "How dev mode is unlocked, when it exists.", "nullable": true }, "facilitator": { "type": "string", "description": "URL of the facilitator that verifies and settles the payment." }, "asset": { "type": "string", "description": "Accepted currency — always `USDC`." }, "asset_address": { "type": "string", "description": "USDC contract on the network above." }, "faucet": { "type": "string", "description": "Test-USDC faucet; only on base-sepolia.", "nullable": true }, "wallets": { "type": "object", "description": "Links to wallets that speak x402 (metamask, coinbase, base_app)." }, "product": { "type": "string", "description": "Name of the product charging." }, "free_max_tabs": { "type": "integer", "description": "Free tabs per owner." }, "prices": { "allOf": [ { "$ref": "#/components/schemas/Precos" } ], "description": "What each paid action costs, in USD." }, "usage": { "allOf": [ { "$ref": "#/components/schemas/Uso" } ], "description": "How much of the free allowance has been used." }, "trial": { "allOf": [ { "$ref": "#/components/schemas/Trial" } ], "description": "The account's trial, when there is a session." } }, "required": [ "provider", "mode", "network", "chain_id", "pay_to", "homolog", "dev", "dev_gate", "facilitator", "asset", "asset_address", "faucet", "wallets", "product", "free_max_tabs", "prices", "usage", "trial" ], "description": "Everything that decides whether the next call will cost: the x402 configuration, the prices, the usage and the trial." }, "Precos": { "type": "object", "properties": { "extra_tab_usd": { "type": "number", "description": "Cost of a tab beyond the allowance." }, "contact_agent_usd": { "type": "number", "description": "Cost of an agent contact." } }, "required": [ "extra_tab_usd", "contact_agent_usd" ], "description": "Prices in force, in dollars. Read them here, not from the documentation." }, "Uso": { "type": "object", "properties": { "tabs": { "type": "integer", "description": "Tabs open now." }, "free_slots_left": { "type": "integer", "description": "Free tabs still available." } }, "required": [ "tabs", "free_slots_left" ], "description": "How much of the free allowance the owner has used." }, "Trial": { "type": "object", "properties": { "days": { "type": "integer", "description": "Trial length in days." }, "active": { "type": "boolean", "description": "Whether it is in force now." }, "days_left": { "type": "integer", "description": "How many days remain." }, "ends_at": { "type": "string", "description": "When it ends (UTC).", "nullable": true }, "granted": { "type": "boolean", "description": "`true` when THIS call granted the trial." } }, "required": [ "days", "active", "ends_at" ], "description": "The paywall-free period that confirming the e-mail grants. It is the alternative to paying." }, "Conta": { "type": "object", "properties": { "id": { "type": "string", "description": "ID of the account." }, "email": { "type": "string", "description": "E-mail confirmed by code." } }, "required": [ "id", "email" ], "description": "The person behind the session." }, "Metricas": { "type": "object", "properties": { "app": { "type": "string", "description": "Product name." }, "today": { "type": "string", "description": "Reference day (UTC, YYYY-MM-DD)." }, "today_visits": { "type": "integer", "description": "Visits counted today." }, "today_contacts": { "type": "integer", "description": "Contact messages received today. Only with `METRICS_TOKEN`: contact does not leave without a token." }, "days": { "type": "array", "items": { "type": "object" }, "description": "One record per day of the window, with the counts of each metric." }, "usage": { "type": "object", "description": "Usage per product resource — here, audits and tabs." }, "accounts": { "type": "object", "description": "Total guests and accounts." }, "financeiro": { "type": "object", "description": "Aggregate of the day: `hoje_usd`, `hoje_count`, `rede`. Only with `METRICS_TOKEN`: money does not leave without a token; the full series is `payments`." }, "payments": { "type": "object", "description": "Finance summary; only with METRICS_TOKEN." }, "achados": { "type": "object", "description": "Which findings appear across stored audits: `audits` (total) and `por_codigo[]` with `code`, `n`, `audits` and `fracao_audits`. Aggregate, no URL and no owner; 1 h cache. `null` if the database did not answer.", "nullable": true } }, "required": [ "app", "today", "today_visits", "days", "usage", "accounts", "achados" ], "description": "7-day panel. `payments` only shows with the operator token and only on Base mainnet." } } }, "paths": { "/okf/{arquivo}": { "get": { "operationId": "get_okf_by_arquivo", "summary": "OKF bundle (Open Knowledge Format v0.1): markdown with frontmatter so an agent reads the whole product without parsing HTML.", "description": "Returns: `text/markdown`. Start at `/okf/index.md`, which lists the bundle.", "security": [], "parameters": [ { "name": "arquivo", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "`text/markdown`. Start at `/okf/index.md`, which lists the bundle." }, "404": { "description": "File outside the bundle." } } } }, "/.well-known/{arquivo}": { "get": { "operationId": "get_well_known_by_arquivo", "summary": "Machine discovery before the home page: `api-catalog` (RFC 9727, a linkset with the API and the MCP), `security.txt` (RFC 9116) and `mcp-registry-auth` (the official MCP registry key).", "description": "Returns: `application/linkset+json` for the api-catalog; `text/plain` for the other two.", "security": [], "parameters": [ { "name": "arquivo", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "`application/linkset+json` for the api-catalog; `text/plain` for the other two." }, "404": { "description": "Name outside the four published." } } } }, "/apis.json": { "get": { "operationId": "get_apis_json", "summary": "APIs.json (apisjson.org, 0.19): the index APIs.io harvests — the API, the MCP, OpenAPI, guide and OKF bundle in one file. Also at `/.well-known/apis.json`.", "description": "Returns: `application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`.", "security": [], "responses": { "200": { "description": "`application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`." } } } }, "/api/": { "get": { "operationId": "api_index", "summary": "Self-describing index: the whole API surface, with quota and retention policy.", "description": "Returns: { name, description, build, base_url, docs, conventions, auth, endpoints, data_retention, quota, mcp, quickstart }", "security": [], "responses": { "200": { "description": "{ name, description, build, base_url, docs, conventions, auth, endpoints, data_retention, quota, mcp, quickstart }", "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "description": "Product name." }, "description": { "type": "string", "description": "What the product does, in one sentence." }, "build": { "type": "string", "description": "Deployed commit." }, "base_url": { "type": "string", "description": "Origin this API is serving from." }, "docs": { "type": "object", "description": "Links to llms.txt, llms-full.txt, openapi.json, MCP and the UI." }, "conventions": { "type": "object", "description": "Error format, CORS, x402 and the UI↔API parity rule." }, "auth": { "type": "object", "description": "Each authentication mode and how to obtain it." }, "endpoints": { "type": "array", "items": { "type": "object" }, "description": "Every endpoint with method, path, auth, absolute URL and what it returns." }, "data_retention": { "type": "object", "description": "What is stored from each run and what is discarded." }, "quota": { "type": "object", "description": "What is free, what costs and how to pay — before you spend a call." }, "mcp": { "type": "object", "description": "Address and transport of the MCP server." }, "quickstart": { "type": "array", "items": { "type": "string" }, "description": "The calls that take you from zero to the first report." } }, "required": [ "name", "description", "build", "base_url", "docs", "conventions", "auth", "endpoints", "data_retention", "quota", "mcp", "quickstart" ] } } } } } } }, "/api/health": { "get": { "operationId": "health", "summary": "Liveness and the commit deployed right now — it is how the smoke waits for its own deploy.", "description": "Returns: { ok, app, build, ts }", "security": [], "responses": { "200": { "description": "{ ok, app, build, ts }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true` when the Worker answers." }, "app": { "type": "string", "description": "Product name." }, "build": { "type": "string", "description": "Deployed commit; CI passes the short SHA on deploy." }, "ts": { "type": "string", "description": "Time of the response (UTC, ISO-8601)." } }, "required": [ "ok", "app", "build", "ts" ] } } } } } } }, "/mcp": { "post": { "operationId": "post_mcp", "summary": "MCP server over HTTP (Streamable HTTP, JSON-RPC 2.0) — plugs into the client with nothing to install.", "description": "The tools are the operations of this same catalog; the MCP has no backend of its own. `GET /mcp` returns the server card.\nReturns: JSON-RPC 2.0 response (`initialize`, `tools/list` or `tools/call`).\nCredentials go in the usual headers (X-Guest-Token, Authorization, X-PAYMENT) and are forwarded to the API.\nAn exhausted quota comes back as a 402 with accepts[] inside the tool result — pay and repeat.", "security": [], "responses": { "200": { "description": "JSON-RPC 2.0 response (`initialize`, `tools/list` or `tools/call`)." } } } }, "/api/audit": { "post": { "operationId": "audit_url", "summary": "Audits a URL and returns the full report in one call, without a token or a tab.", "description": "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: sign up and confirm the e-mail to get the trial.\nReturns: { id, score, issues[{severity,code,message}], summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap}, 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} }", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "description": "The page to audit, `http` or `https`." }, "guest_token": { "type": "string", "description": "Guest `pa_…` so the audit is tied to it and shows up in the tabs." }, "cf_turnstile_response": { "type": "string", "description": "Turnstile response; it is the human path, agents use x402." } }, "required": [ "url" ] }, "example": { "url": "https://example.com/", "guest_token": "pa_… (optional, ties the audit)" } } } }, "responses": { "200": { "description": "{ id, score, issues[{severity,code,message}], summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap}, 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} }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Audit" } } } }, "400": { "description": "Body is not JSON, or `url` missing/not http." }, "402": { "description": "Quota exceeded. The response carries `accepts[]` (x402, USDC on Base): pay and repeat the same call with `X-PAYMENT`." }, "403": { "description": "Wrong Turnstile answer. A wrong captcha is not an invitation to pay." }, "429": { "description": "Past `MAX_AUDITS_PER_HOUR` on the same IP. Wait an hour." } } } }, "/api/audits/{id}": { "get": { "operationId": "get_audit", "summary": "Re-reads an audit already made, in full, without re-auditing the page.", "description": "Re-reading costs nothing and does not count against the allowance — the page's HTML is not kept, but the report is.\nReturns: { audit_id, url, score, summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap}, counts{errors,warnings,info}, issues[{severity,code,message}], fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], jsonLd, headers, truncated, share_slug, created_at }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ audit_id, url, score, summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap}, counts{errors,warnings,info}, issues[{severity,code,message}], fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], jsonLd, headers, truncated, share_slug, created_at }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuditGravado" } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } } }, "/api/audits/{id}/patch": { "get": { "operationId": "get_patch", "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.", "description": "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.\nReturns: { 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 }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ 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 }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Patch" } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } } }, "/api/tools": { "get": { "operationId": "list_tools", "summary": "The micro-tools: one landing per check, all driven by the same engine as the audit.", "description": "Returns: { tools[{slug,title,h1,description,lead,category,icon,checks,serp,sections,_links}], _links }", "security": [], "responses": { "200": { "description": "{ tools[{slug,title,h1,description,lead,category,icon,checks,serp,sections,_links}], _links }", "content": { "application/json": { "schema": { "type": "object", "properties": { "tools": { "type": "array", "items": { "$ref": "#/components/schemas/Ferramenta" }, "description": "Every published tool." }, "_links": { "type": "object", "description": "The hub in HTML and the API index." } }, "required": [ "tools", "_links" ] } } } } } } }, "/api/tools/{slug}": { "get": { "operationId": "get_tool", "summary": "Metadata and copy of one micro-tool.", "description": "Returns: { slug, title, h1, description, lead, category, icon, checks, serp, sections, _links }", "security": [], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ slug, title, h1, description, lead, category, icon, checks, serp, sections, _links }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ferramenta" } } } }, "404": { "description": "Unknown slug." } } } }, "/tools": { "get": { "operationId": "get_tools", "summary": "HTML hub of the micro-tools, indexable. For JSON use `GET /api/tools`.", "description": "Returns: `text/html` — the hub page, rendered on the server.", "security": [], "responses": { "200": { "description": "`text/html` — the hub page, rendered on the server." } } } }, "/tools/{slug}": { "get": { "operationId": "get_tools_by_slug", "summary": "HTML landing of one check, indexable. An unknown slug returns a real 404.", "description": "The 404 is real, not a 200 with an empty shell: mass soft-404s burn the whole domain in the index.\nReturns: `text/html` — the tool's landing.", "security": [], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "`text/html` — the tool's landing." }, "404": { "description": "Unknown slug — a real 404, not an empty shell." } } } }, "/api/audits/{id}/share": { "post": { "operationId": "post_api_audits_by_id_share", "summary": "Publishes the audit under a non-enumerable slug. Calling again returns the same slug.", "description": "Returns: { ok, shared, slug, path, badge, _links }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ ok, shared, slug, path, badge, _links }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Compartilhamento" } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } }, "delete": { "operationId": "delete_api_audits_by_id_share", "summary": "Revokes the share; the slug stops serving the report.", "description": "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.\nReturns: { ok, shared }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ ok, shared }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "shared": { "type": "boolean", "description": "Always `false` at the end of this call." } }, "required": [ "ok", "shared" ] } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } } }, "/api/shared/{slug}": { "get": { "operationId": "get_api_shared_by_slug", "summary": "Shared report as JSON, without credentials — the machine twin of `/r/:slug`.", "description": "Returns: { audit_id, url, score, summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap}, counts{errors,warnings,info}, issues[{severity,code,message}], fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], jsonLd, headers, truncated, share_slug, created_at }", "security": [], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ audit_id, url, score, summary{finalUrl,status,contentType,title,metaDescription,canonical,robots,viewport,charset,lang,favicon,faviconSource,h1s,openGraph,twitter,jsonLdCount,jsonLdBlocks,jsonLdDropped,jsonLdTypes,images,links,words,hreflang,legacy,redirects,robotsTxt,sitemap}, counts{errors,warnings,info}, issues[{severity,code,message}], fixes[{code,severity,classe,alvo,snippet,arquivo,fonte,nota}], jsonLd, headers, truncated, share_slug, created_at }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuditGravado" } } } }, "404": { "description": "Unknown slug, or share revoked." } } } }, "/r/{slug}": { "get": { "operationId": "get_r_by_slug", "summary": "HTML page of the shared report, with `noindex`.", "description": "`noindex` on purpose: a third party's report is not our content to index. The JSON twin is `/api/shared/:slug`.\nReturns: `text/html` — the rendered report, with `noindex`.", "security": [], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "`text/html` — the rendered report, with `noindex`." }, "404": { "description": "Unknown or revoked slug." } } } }, "/api/badge/{slug}": { "get": { "operationId": "get_badge", "summary": "Metadata of the score badge, including the markdown ready for the README.", "description": "Returns: { slug, score, label, available, markdown, _links }", "security": [], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ slug, score, label, available, markdown, _links }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Badge" } } } }, "404": { "description": "Unknown slug. Revoked is different: it returns 200 with `available: false`." } } } }, "/badge/{slug}.svg": { "get": { "operationId": "get_badge_by_slug_svg", "summary": "SVG score badge, to paste in the README of the audited project.", "description": "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.\nReturns: `image/svg+xml` — the badge, coloured by the score or grey `n/a` if revoked.", "security": [], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "`image/svg+xml` — the badge, coloured by the score or grey `n/a` if revoked." }, "404": { "description": "Malformed slug." } } } }, "/api/guest": { "post": { "operationId": "create_guest", "summary": "Creates a guest `pa_…` — it is what gives access to the tab workspace without an account.", "description": "Keep the token: it is the identity of the tabs and of the audits tied to them.\nReturns: { token }", "security": [], "responses": { "200": { "description": "{ token }", "content": { "application/json": { "schema": { "type": "object", "properties": { "token": { "type": "string", "description": "The guest, prefix `pa_`. Send it in `X-Guest-Token`, as Bearer or in `?guest_token=`." } }, "required": [ "token" ] } } } } } } }, "/api/tabs": { "get": { "operationId": "list_tabs", "summary": "The owner's whole workspace, with the active tab's result already rehydrated.", "description": "One call draws the whole screen: tabs, the focused tab, its last report, remaining allowance and prices.\nReturns: { tabs[{id,url,alias,active,audit_id,score,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 }", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "{ tabs[{id,url,alias,active,audit_id,score,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 }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workspace" } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." } } }, "post": { "operationId": "create_tab", "summary": "Opens a tab for the URL, or focuses the one that already exists for it.", "description": "Past the free tab allowance it answers 402 with `accepts[]`: pay and repeat.\nReturns: { ok, tab{id,url,alias,active,audit_id,score,created_at} }", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "description": "The URL the tab will follow." }, "alias": { "type": "string", "description": "Label to recognise the tab in the list." } }, "required": [ "url" ] }, "example": { "url": "https://example.com/", "alias": "optional label" } } } }, "responses": { "200": { "description": "{ ok, tab{id,url,alias,active,audit_id,score,created_at} }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "tab": { "allOf": [ { "$ref": "#/components/schemas/Aba" } ], "description": "The opened tab (or the one that already existed for that URL)." } }, "required": [ "ok", "tab" ] } } } }, "400": { "description": "`url` missing or not http." }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "402": { "description": "Quota exceeded. The response carries `accepts[]` (x402, USDC on Base): pay and repeat the same call with `X-PAYMENT`." } } } }, "/api/tabs/{id}": { "get": { "operationId": "get_api_tabs_by_id", "summary": "One tab with the full report of its last run.", "description": "Returns: { tab{id,url,alias,active,audit_id,score,created_at}, result{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at} }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ tab{id,url,alias,active,audit_id,score,created_at}, result{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at} }", "content": { "application/json": { "schema": { "type": "object", "properties": { "tab": { "allOf": [ { "$ref": "#/components/schemas/Aba" } ], "description": "The requested tab." }, "result": { "allOf": [ { "$ref": "#/components/schemas/AuditGravado" } ], "description": "The report of the last run; `null` if the tab never ran.", "nullable": true } }, "required": [ "tab", "result" ] } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } }, "patch": { "operationId": "patch_api_tabs_by_id", "summary": "Renames the tab or puts it in focus.", "description": "Returns: { ok, tab{id,url,alias,active,audit_id,score,created_at} }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "alias": { "type": "string", "description": "New label of the tab." }, "active": { "type": "boolean", "description": "`true` focuses this tab (and unfocuses the other)." } } }, "example": { "alias": "new label", "active": true } } } }, "responses": { "200": { "description": "{ ok, tab{id,url,alias,active,audit_id,score,created_at} }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "tab": { "allOf": [ { "$ref": "#/components/schemas/Aba" } ], "description": "The tab with the change applied." } }, "required": [ "ok", "tab" ] } } } }, "400": { "description": "No changeable field in the body." }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } }, "delete": { "operationId": "delete_api_tabs_by_id", "summary": "Closes the tab. Its audit history keeps existing.", "description": "Returns: { ok }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ ok }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } } }, "/api/tabs/{id}/run": { "post": { "operationId": "run_tab", "summary": "Re-audits the tab's URL and stores a new report.", "description": "Consumes the same daily allowance as `POST /api/audit` — past it, 402 with `accepts[]`.\nReturns: { ok, tab{id,url,alias,active,audit_id,score,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} }", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "{ ok, tab{id,url,alias,active,audit_id,score,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} }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "tab": { "allOf": [ { "$ref": "#/components/schemas/Aba" } ], "description": "The tab with the new run's score." }, "gate": { "allOf": [ { "$ref": "#/components/schemas/Gate" } ], "description": "How much of the allowance is left after this run." }, "result": { "allOf": [ { "$ref": "#/components/schemas/AuditGravado" } ], "description": "The report just stored." } }, "required": [ "ok", "tab", "gate", "result" ] } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." }, "402": { "description": "Quota exceeded. The response carries `accepts[]` (x402, USDC on Base): pay and repeat the same call with `X-PAYMENT`." }, "404": { "description": "The resource does not exist (or is not yours — the API does not tell the two apart on purpose)." } } } }, "/api/gate": { "get": { "operationId": "get_api_gate", "summary": "How many free audits remain for this IP and whether Turnstile is about to be required.", "description": "Check before spending a call: it is the number IN FORCE, not the allowance in the documentation.\nReturns: { ip, now, configured, free_allowance, free_remaining, verified_until, needs_verification, sitekey }", "security": [], "responses": { "200": { "description": "{ ip, now, configured, free_allowance, free_remaining, verified_until, needs_verification, sitekey }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Gate" } } } } } } }, "/api/billing": { "get": { "operationId": "billing", "summary": "Tab allowance, prices, full x402 configuration and the state of the trial.", "description": "Returns: { provider, mode, network, chain_id, pay_to, homolog, dev, dev_gate, 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,granted?} }", "security": [], "responses": { "200": { "description": "{ provider, mode, network, chain_id, pay_to, homolog, dev, dev_gate, 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,granted?} }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Billing" } } } } } } }, "/api/me": { "get": { "operationId": "get_api_me", "summary": "The session's account, its last 50 audits and the state of the trial.", "description": "Returns: { user{id,email}, audits[{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at}], trial{days,active,days_left?,ends_at,granted?} }", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "{ user{id,email}, audits[{audit_id,url,score,summary,counts,issues,fixes,jsonLd,headers,truncated,share_slug,created_at}], trial{days,active,days_left?,ends_at,granted?} }", "content": { "application/json": { "schema": { "type": "object", "properties": { "user": { "allOf": [ { "$ref": "#/components/schemas/Conta" } ], "description": "The person who owns the session." }, "audits": { "type": "array", "items": { "$ref": "#/components/schemas/AuditGravado" }, "description": "The account's 50 most recent audits." }, "trial": { "allOf": [ { "$ref": "#/components/schemas/Trial" } ], "description": "The account's trial: how many days, whether active and when it ends." } }, "required": [ "user", "audits", "trial" ] } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." } } } }, "/api/auth/start": { "post": { "operationId": "post_api_auth_start", "summary": "Sends the 6-digit code by e-mail to create the account or sign in to it.", "description": "Returns: { ok }", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "description": "E-mail that will receive the code." } }, "required": [ "email" ] }, "example": { "email": "you@example.com" } } } }, "responses": { "200": { "description": "{ ok }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "400": { "description": "E-mail missing or malformed." }, "429": { "description": "Too many requests for the same e-mail." } } } }, "/api/auth/verify": { "post": { "operationId": "post_api_auth_verify", "summary": "Exchanges the code for a session — and confirming the e-mail grants the trial on the spot.", "description": "It is the alternative to paying: confirming the e-mail is worth a period of full access, without going through the 402.\nReturns: { ok, token, user{id,email}, trial{days,active,days_left?,ends_at,granted?} }", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "description": "The same e-mail as in `/api/auth/start`." }, "code": { "type": "string", "description": "The 6 digits that arrived by e-mail." } }, "required": [ "email", "code" ] }, "example": { "email": "you@example.com", "code": "123456" } } } }, "responses": { "200": { "description": "{ ok, token, user{id,email}, trial{days,active,days_left?,ends_at,granted?} }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true` when the code matched." }, "token": { "type": "string", "description": "Session `sess_…` to use in `Authorization: Bearer`." }, "user": { "allOf": [ { "$ref": "#/components/schemas/Conta" } ], "description": "The person who just signed in." }, "trial": { "allOf": [ { "$ref": "#/components/schemas/Trial" } ], "description": "The trial, with `granted: true` when this call is the one that granted it." } }, "required": [ "ok", "token", "user", "trial" ] } } } }, "400": { "description": "Wrong or expired code." }, "429": { "description": "Too many attempts." } } } }, "/api/auth/claim": { "post": { "operationId": "post_api_auth_claim", "summary": "Moves the guest's audits and tabs to the signed-in account.", "description": "Returns: { ok, claimed }", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "guest_token": { "type": "string", "description": "Guest `pa_…` whose content moves to the account." } }, "required": [ "guest_token" ] }, "example": { "guest_token": "pa_…" } } } }, "responses": { "200": { "description": "{ ok, claimed }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "claimed": { "type": "integer", "description": "How many records changed owner." } }, "required": [ "ok", "claimed" ] } } } }, "400": { "description": "`guest_token` missing." }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." } } } }, "/api/auth/logout": { "post": { "operationId": "post_api_auth_logout", "summary": "Invalidates the current session.", "description": "Returns: { ok }", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "{ ok }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "401": { "description": "No credential, or an invalid one. See this endpoint's auth." } } } }, "/api/contact": { "post": { "operationId": "contact", "summary": "Talks to support: a human solves Turnstile, an agent pays $0.10 in x402.", "description": "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`.\nReturns: { ok, path }", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "description": "What to call the person writing." }, "email": { "type": "string", "description": "Where to reply." }, "message": { "type": "string", "description": "What you want to say." }, "form_ts": { "type": "integer", "description": "When the form was opened; it is the anti-robot of the human path." }, "cf_turnstile_response": { "type": "string", "description": "Turnstile response; present only on the human path." } }, "required": [ "name", "email", "message" ] }, "example": { "name": "…", "email": "a@example.com", "message": "…", "form_ts": 0, "cf_turnstile_response": "(human)" } } } }, "responses": { "200": { "description": "{ ok, path }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true` when the message was accepted." }, "path": { "type": "string", "description": "Which path it came through: human with captcha or paid agent." } }, "required": [ "ok", "path" ] } } } }, "400": { "description": "Required field missing." }, "402": { "description": "Quota exceeded. The response carries `accepts[]` (x402, USDC on Base): pay and repeat the same call with `X-PAYMENT`." }, "429": { "description": "Agent backoff: wait for `Retry-After`." } } } }, "/api/visit": { "post": { "operationId": "post_api_visit", "summary": "Ping from the interface that increments the day's visits. Agents need not call it.", "description": "Smoke does not count: `X-MM-Smoke`, User-Agent `mm-smoke` or `smoke: true` in the body come in as `counted: false`.\nReturns: { ok, counted, reason? }", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "p": { "type": "string", "description": "Path of the visited page." }, "smoke": { "type": "boolean", "description": "`true` marks the call as a test and it does not enter the count." } } }, "example": { "p": "/" } } } }, "responses": { "200": { "description": "{ ok, counted, reason? }", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Always `true`." }, "counted": { "type": "boolean", "description": "Whether the visit entered the day's count." }, "reason": { "type": "string", "description": "Why it did not count, when `counted` is `false`." } }, "required": [ "ok", "counted" ] } } } } } } }, "/api/metrics": { "get": { "operationId": "get_api_metrics", "summary": "Metrics of the last 7 days and the most frequent findings across audits. With the operator token, includes payments.", "description": "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.\nReturns: { app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments?, achados }", "security": [], "parameters": [ { "name": "Authorization", "in": "header", "required": false, "schema": { "type": "string" }, "description": "`Bearer <METRICS_TOKEN>` to include the finance block." } ], "responses": { "200": { "description": "{ app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments?, achados }", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Metricas" } } } } } } }, "/api/credito": { "post": { "operationId": "post_api_credito", "summary": "Top up prepaid credit: pay once with x402 and get the token that debits on any API of the house.", "description": "Returns: { token, saldo_usd, guarde, usar, saldo_em }", "security": [], "parameters": [ { "name": "usd", "in": "query", "required": true, "schema": { "type": "integer" }, "description": "Package: 1, 5, 10 ou 25 dollars." } ], "responses": { "200": { "description": "{ token, saldo_usd, guarde, usar, saldo_em }", "content": { "application/json": { "schema": { "type": "object", "properties": { "token": { "type": "string", "description": "Bearer token for the balance (`cred_…`). Shown ONCE — it cannot be recovered." }, "saldo_usd": { "type": "string", "description": "Credited balance." }, "guarde": { "type": "string", "description": "Warning that the token is the bearer of the credit." }, "usar": { "type": "string", "description": "How to present the token on paid routes." }, "saldo_em": { "type": "string", "description": "Where to check balance and statement." } }, "required": [ "token", "saldo_usd", "guarde", "usar", "saldo_em" ] } } } }, "400": { "description": "Package outside the list (1, 5, 10 ou 25)." }, "402": { "description": "Unpaid — the body carries the x402 `accepts[]`." } } }, "get": { "operationId": "get_api_credito", "summary": "Credit balance and statement — the latest movements, without returning the token.", "description": "Returns: { saldo_micros, saldo_usd, criado_em, movimentos }", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "{ saldo_micros, saldo_usd, criado_em, movimentos }", "content": { "application/json": { "schema": { "type": "object", "properties": { "saldo_micros": { "type": "integer", "description": "Balance in micro-dollars (1e-6 USD)." }, "saldo_usd": { "type": "string", "description": "Formatted balance." }, "criado_em": { "type": "string", "description": "When the credit was opened." }, "movimentos": { "type": "array", "items": { "type": "object" }, "description": "Recent credits and debits, with product and resource." } }, "required": [ "saldo_micros", "saldo_usd", "criado_em", "movimentos" ] } } } }, "401": { "description": "No token, or unknown token." } } } } } }