api

POST /api/public/audit

Rode uma auditoria SEO anónima one-shot sem chave API. Resposta síncrona em menos de 60s, 1 por IP a cada 24h, sem Core Web Vitals.

O que este endpoint faz

POST /api/public/audit roda uma auditoria SEO síncrona em qualquer URL público sem chave API. Devolve o envelope completo da auditoria na mesma resposta: pontuação total, pontuações por módulo e findings ao nível de regra. PageSpeed Insights é pulado para manter a chamada barata e a resposta abaixo de 60 segundos.

  • Síncrono: bloqueia até a auditoria terminar, sem polling.
  • Anónimo: identificado pelo IP do cliente, limitado a 1 auditoria por IP a cada 24h.
  • Pula Core Web Vitals (LCP, CLS, INP). Para dados PSI, use o POST /api/audits autenticado.
  • O resultado não é persistido numa conta de utilizador: uma linha de rate-limit é guardada na tabela audits com user_id = NULL.

Por que importa

A auditoria anónima é o caminho de menor fricção para o widget “free audit” da página inicial e para ferramentas de terceiros que querem mostrar a pontuação da MetricSpot antes de pedir ao utilizador para se registar. Sem OAuth, sem geração de chaves, sem plano: apenas um POST HTTPS.

Fluxos concretos:

  • Um construtor de landing page incorpora um formulário “teste o seu site” que chama o endpoint diretamente do browser do utilizador e renderiza a pontuação inline.
  • Um bot Slack aceita /audit example.com de qualquer colega e devolve a pontuação sem ninguém no workspace precisar de autenticar contra a MetricSpot.

Como usar

Envie um POST com um corpo JSON contendo url. O URL deve ser absoluto (https://...), parseável e ter no máximo 2000 caracteres.

Requisição

POST /api/public/audit HTTP/1.1
Host: app.metricspot.com
Content-Type: application/json

{ "url": "https://example.com" }

curl

curl -X POST https://app.metricspot.com/api/public/audit \
  -H "content-type: application/json" \
  -d '{"url": "https://example.com"}'

Node fetch

const res = await fetch("https://app.metricspot.com/api/public/audit", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ url: "https://example.com" }),
});
const { audit } = await res.json();
console.log(`Pontuação ${audit.total_score} para ${audit.domain}`);

Python httpx

import httpx

r = httpx.post(
    "https://app.metricspot.com/api/public/audit",
    json={"url": "https://example.com"},
    timeout=90.0,
)
print(r.json()["audit"]["total_score"])

Resposta

200 OK com o envelope completo da auditoria:

{
  "audit": {
    "url": "https://example.com",
    "domain": "example.com",
    "total_score": 78,
    "module_scores": {
      "technical": 92,
      "onpage": 71,
      "performance": null,
      "ai": 65,
      "modern_seo": 80,
      "social": 88,
      "accessibility": 74,
      "privacy": 82,
      "readability": 70,
      "tech_stack": 100,
      "organic_traffic": 100
    },
    "rules": [
      {
        "module": "onpage",
        "rule_id": "onpage.meta-description",
        "passed": false,
        "severity": "major",
        "title": "Missing meta description",
        "recommendation": "Add a 140-160 character meta description summarizing the page.",
        "data": {}
      }
    ]
  },
  "note": "Anonymous audits are limited and do not include Core Web Vitals. Sign up free for full audits and PDF reports."
}

Campos:

  • audit.url: o URL auditado, ecoado de volta.
  • audit.domain: hostname extraído do URL.
  • audit.total_score: pontuação ponderada em todos os módulos, 0 a 100.
  • audit.module_scores: pontuação por módulo 0 a 100, ou null quando o módulo foi pulado (performance é sempre null para auditorias anónimas).
  • audit.rules: array de cada regra avaliada. Cada entrada tem module, rule_id, passed (boolean), severity (info | minor | major | critical), title, recommendation opcional, e data (payload específico da regra).
  • note: string a explicar os limites anónimos, para exibir na UI.

Envelope de erro

{ "error": "Rate limit reached", "message": "Sign up free for more reports." }

Erros comuns

CódigoQuandoAção
INVALID_URL (400)URL não parseável, sem esquema ou > 2000 caracteresPasse um URL absoluto https://
RATE_LIMITED (429)IP já auditou nas últimas 24hAguarde 24h, ou registe-se num plano Free (10 auditorias/mês)
UPSTREAM_FAILED (502)Falha do crawlerTente novamente com backoff curto
INTERNAL (500)Erro de backend inesperadoTente novamente; se persistir, faça login e use POST /api/audits para um retry enfileirado

O endpoint não devolve 401, 402 ou 404: é não-autenticado por design e não tem recursos para olhar.

Perguntas frequentes

Por que performance é sempre null?

O endpoint anónimo pula o Google PageSpeed Insights para manter o tempo total abaixo de 60 segundos e evitar queimar quota PSI em tráfego não-limitado. Para Core Web Vitals (LCP, CLS, INP), use o POST /api/audits autenticado, que roda PSI em paralelo com o crawler.

Como o rate limit é aplicado?

Uma linha é inserida na tabela audits em cada execução anónima com user_id = NULL e ip_address definido para o IP do chamador. Chamadas subsequentes do mesmo IP em 24h devolvem 429. O IP é lido dos cabeçalhos padrão de proxy reverso (X-Forwarded-For), então auditorias atrás de um proxy partilhado podem colidir.

Posso usar isto a partir do browser?

Sim. O endpoint define CORS permissivo para metricspot.com e aceita POSTs cross-origin. Para o seu próprio domínio, rode uma função serverless como proxy fino: permite adicionar rate limiting por tenant e evita expor IPs dos seus visitantes à MetricSpot.

O resultado é persistido em algum lugar?

Existe uma linha para fins de rate-limit, mas não está ligada a qualquer conta e não é visível em painel nenhum. Para guardar e revisitar uma auditoria, registe-se grátis e chame POST /api/audits.

Fontes

Última atualização 2026-05-14