api
POST /api/audits
Metti in coda un audit SEO completo con Core Web Vitals. Restituisce audit_id + status: queued in 1-2s. Conta contro il piano, rispetta cooldown per dominio.
Cosa fa questo endpoint
POST /api/audits mette in coda un audit SEO e di leggibilità per IA completo, restituendo la busta dell’audit immediatamente. È la controparte autenticata e completa di POST /api/public/audit.
- Mette in coda in modo asincrono e restituisce in 1-2 secondi con
status: "queued"e unaudit_idreale. - Tira Core Web Vitals (LCP, CLS, INP) dal Google PageSpeed Insights come parte dell’esecuzione.
- Conta contro la quota del piano (Free 10/mese, Starter 50/mese, Pro illimitato).
- Rispetta cooldown per dominio: 24 ore tra audit dello stesso URL esatto, più un breve cooldown globale tra due audit qualsiasi.
- Restituisce la stessa forma di
GET /api/audits/:id. I findings sono vuoti fino a quando l’audit non transita acompleted.
Perché è importante
POST /api/audits è l’endpoint giusto quando hai bisogno di un audit persistente che puoi recuperare più tardi, un PDF, dati di traffico organico, o Core Web Vitals. Gli audit anonimi coprono circa 90 check ma saltano PSI; questo endpoint copre tutto.
Flussi concreti:
- Un bot audit-on-PR chiama
POST /api/auditsquando un preview deploy parte, cattura l’audit_id, pollaGET /api/audits/:idogni 5 secondi fino a 60 secondi, e posta un commento delta contro l’ultimo audit sullo stesso URL. - Un agent cron settimanale itera le landing page più visitate dell’utente e mette in coda un audit fresco per ognuna, poi invia un digest da
GET /api/audits.
Come usarlo
L’endpoint è async per design. Tratta la risposta immediata 201 Created come acknowledgement, poi polla GET /api/audits/:id con l’audit_id restituito ogni pochi secondi. Il completamento end-to-end tipico è 10 a 30 secondi; permetti fino a 90 secondi per target lenti.
Richiesta
POST /api/audits HTTP/1.1
Host: app.metricspot.com
Authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
{ "url": "https://example.com" }
Il campo url è obbligatorio, deve essere assoluto (https://...), parsabile e al massimo 2000 caratteri.
curl
curl -X POST https://app.metricspot.com/api/audits \
-H "authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "content-type: application/json" \
-d '{"url": "https://example.com"}'
Node (in coda + polling)
const headers = {
authorization: "Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"content-type": "application/json",
};
const queueRes = await fetch("https://app.metricspot.com/api/audits", {
method: "POST",
headers,
body: JSON.stringify({ url: "https://example.com" }),
});
const { audit } = await queueRes.json();
const id = audit.id;
while (true) {
await new Promise((r) => setTimeout(r, 3000));
const r = await fetch(`https://app.metricspot.com/api/audits/${id}`, { headers });
const data = await r.json();
if (["completed", "failed"].includes(data.audit.status)) {
console.log(data.audit.status, data.audit.score);
break;
}
}
Python httpx
import httpx, time
HEADERS = {"authorization": "Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx"}
r = httpx.post(
"https://app.metricspot.com/api/audits",
headers=HEADERS,
json={"url": "https://example.com"},
timeout=30.0,
)
audit_id = r.json()["audit"]["id"]
for _ in range(30):
time.sleep(3)
r = httpx.get(f"https://app.metricspot.com/api/audits/{audit_id}", headers=HEADERS, timeout=30.0)
audit = r.json()["audit"]
if audit["status"] in ("completed", "failed"):
print(audit["status"], audit["score"])
break
Risposta
201 Created:
{
"audit": {
"id": 12345,
"domain": "example.com",
"url": "https://example.com",
"status": "queued",
"score": null,
"created_at": "2026-05-14T10:18:04.000Z"
}
}
Campi sulla risposta in coda:
id: id intero dell’audit, usato in ogni chiamata successiva (GET /api/audits/:id, PDF, Google).domain: hostname estratto dall’URL.url: riecheggiato dalla richiesta.status: sempre"queued"sulla risposta iniziale. Transita a"running", poi"completed"o"failed".score:nullfino al completamento dell’audit.created_at: timestamp ISO 8601.
Una volta che status === "completed", GET /api/audits/:id restituisce la busta completa con score, module_scores, e l’array findings (vedi api-get-audit).
Busta di errore
{ "error": "Quota exceeded", "message": "Upgrade to Starter for 50 audits per month." }
Errori comuni
| Codice | Quando | Azione |
|---|---|---|
UNAUTHORIZED (401) | Bearer mancante o non valido | Genera una chiave su app.metricspot.com/settings/api-keys |
QUOTA_EXCEEDED (402) | Quota mensile del piano usata | Upgrade su app.metricspot.com/billing |
INVALID_URL (400) | URL non parsabile o > 2000 caratteri | Passa un URL assoluto https:// |
RATE_LIMITED (429) | Cooldown per dominio o globale | Aspetta la finestra indicata prima di riprovare lo stesso URL |
UPSTREAM_FAILED (5xx) | Glitch PSI o crawler | Riprova con backoff |
Domande frequenti
Quanto tempo fino al completamento dell’audit?
10 a 30 secondi sui siti tipici. Target ricchi di JS o pagine con molti structured data possono richiedere fino a 90 secondi. Polla GET /api/audits/:id ogni 3 a 5 secondi: l’audit è completamente computato quando status passa a completed.
Un audit fallito costa un audit?
Un audit failed non consuma quota del piano. La quota decrementa solo quando l’esecuzione completa con successo e i findings sono memorizzati. I fallimenti di rate-limit PSI sono ritentati internamente prima di emergere.
Perché c’è un cooldown per dominio?
Lo stesso URL auditato due volte in cinque minuti restituisce gli stessi findings: spreca quota PSI e confonde le dashboard di traffico. Il cooldown di 24 ore per URL è applicato lato server. Il messaggio di errore include il timestamp esatto retry_at così i client possono pianificare un re-queue.
Posso mettere in coda molti audit in parallelo?
Sì, fino al cooldown globale (qualche secondo tra due audit qualsiasi per account). Per batch di 50+ URL, spaziali lato client o usa Pro, che alza la quota mensile e stringe il throttle globale.
Fonti
Ultimo aggiornamento 2026-05-14