API Reference

PerSeo Insights REST API v1.0

HTTPS only JSON v1.0.0

Base URL

https://insights.perseodesign.com/api/v1

L'API REST di PerSeo Insights permette di avviare scansioni SEO, leggere i risultati, esportare report e gestire i token di accesso in modo programmatico. Ideale per CI/CD, monitoring automatizzato e integrazioni con tool di terze parti.

Per creare la tua prima API key accedi alla Dashboard, sezione API & Token.

Autenticazione

Tutti gli endpoint richiedono un Bearer token nell'header HTTP:

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

API Key (permanente)

Token a lunga vita creati dalla Dashboard. Iniziano con sk_live_. Usali per script, automazioni e integrazioni server-side.

JWT (sessione 24h)

Token a breve vita emessi da POST /auth/login. Usali per client interattivi che richiedono login esplicito.

Scopes disponibili

ScopeDescrizione
readAccesso in lettura: profilo, history, lista token
scanAvvia nuove scansioni (POST /scans)
exportEsporta risultati (GET /scans/{id}/export/{format})

Rate Limits

I limiti API sono allineati ai limiti del sito web. Il reset avviene ogni 24h (finestra mobile).

TierSingle Scan/giornoSitemap Scan/giorno
Guest (non autenticato)11
Free (registrato)55
Pro5010

Per maggiori dettagli sui piani e le funzionalità, visita la pagina dei Prezzi.

Response Format

Tutte le risposte seguono il formato standard JSON:

Successo

{ "success": true, "data": { ... }, "meta": { "timestamp": "2026-02-25T10:30:00Z", "version": "1.0", "request_id": "550e8400-..." } }

Errore

{ "success": false, "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Scan limit reached (5/5).", "retry_after": 14400 }, "meta": { ... } }

Auth

POST /api/v1/auth/login No auth

Autentica con email/password e riceve un JWT access token (24h).

# Request curl -s -X POST https://insights.perseodesign.com/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"[email protected]","password":"password123"}'
Response 200
{ "success": true, "data": { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 86400, "token_type": "Bearer", "user": { "id": 42, "username": "mario.rossi", "email": "[email protected]" } } }
GET /api/v1/auth/verify JWT Bearer

Verifica la validita' di un JWT token.

Token Management

GET /api/v1/tokens scope: read

Lista tutte le API key dell'utente autenticato.

curl https://insights.perseodesign.com/api/v1/tokens \ -H "Authorization: Bearer sk_live_xxxx"
POST /api/v1/tokens scope: read

Crea una nuova API key. Il token viene mostrato una sola volta.

CampoTipoReq.Descrizione
namestringSIEtichetta del token (max 100 char)
scopesarrayNODefault ["read"]. Valori: read, scan, export
curl -X POST https://insights.perseodesign.com/api/v1/tokens \ -H "Authorization: Bearer sk_live_xxxx" \ -H "Content-Type: application/json" \ -d '{"name":"Script CI","scopes":["read","scan","export"]}'
IMPORTANTE: Il campo token nella risposta viene mostrato una sola volta. Salvalo subito in modo sicuro.
DELETE /api/v1/tokens/{id} scope: read

Revoca (disattiva) permanentemente un'API key.

Scansioni

POST /api/v1/scans scope: scan

Avvia una scansione SEO asincrona. Risponde con 202 Accepted e un scan_id da usare per il polling.

CampoTipoReq.Descrizione
urlstringSIURL da analizzare (http o https)
modestringNOsingle (default) o sitemap
curl -X POST https://insights.perseodesign.com/api/v1/scans \ -H "Authorization: Bearer sk_live_xxxx" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","mode":"single"}'
Response 202 Accepted
{ "success": true, "data": { "scan_id": "a7f3d2e1-8b4c-4f9a-b6d5-c3e2f1a0b9d8", "status": "queued", "mode": "single", "url": "https://example.com", "poll_url": "/api/v1/scans/a7f3d2e1-..." } }
GET /api/v1/scans/{scan_id} scope: read

Recupera stato e risultati di una scansione. Fai polling ogni 2-3 secondi finche' status != "running".

running

In corso

complete

Completata

error

Fallita

stopped

Interrotta

# Polling loop bash while true; do RESULT=$(curl -s \ -H "Authorization: Bearer $TOKEN" \ "https://insights.perseodesign.com/api/v1/scans/$SCAN_ID") STATUS=$(echo $RESULT | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['status'])") [ "$STATUS" != "running" ] && break sleep 3 done

Storico

GET /api/v1/history scope: read

Storico delle scansioni dell'utente con paginazione.

ParametroTipoDefaultDescrizione
pageint1Numero pagina
per_pageint20Risultati per pagina (max 50)
curl "https://insights.perseodesign.com/api/v1/history?page=1&per_page=20" \ -H "Authorization: Bearer sk_live_xxxx"

Esportazione

GET /api/v1/scans/{id}/export/{format} scope: export

Esporta i risultati di una scansione. Formati supportati: json, csv, pdf.

# Scarica CSV curl -H "Authorization: Bearer sk_live_xxxx" \ "https://insights.perseodesign.com/api/v1/scans/127/export/csv" \ -o report.csv

Utente

GET /api/v1/user/profile scope: read

Restituisce il profilo dell'utente autenticato.

GET /api/v1/user/usage scope: read

Statistiche di utilizzo: scan oggi, richieste API, limiti del piano.

Codici di Errore

CodiceHTTPDescrizione
MISSING_AUTH 401 Header Authorization assente o malformato
INVALID_TOKEN 401 Token non valido, scaduto o revocato
INSUFFICIENT_SCOPE 403 Il token non ha lo scope richiesto
INVALID_CREDENTIALS 401 Email/password errate
ACCOUNT_DISABLED 403 Account disabilitato
RATE_LIMIT_EXCEEDED 429 Limite scan o richieste superato
INVALID_REQUEST 400 Parametri mancanti o malformati
INVALID_URL 400 URL non valido
INVALID_SCOPES 400 Scope non riconosciuti
NOT_FOUND 404 Risorsa non trovata
FORBIDDEN 403 Accesso negato (risorsa di un altro utente)
INTERNAL_ERROR 500 Errore interno del server

Esempi d'Uso

Flusso completo: login + crea token + prima scansione (Bash)

# 1. Login e ottieni JWT JWT=$(curl -s -X POST https://insights.perseodesign.com/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"[email protected]","password":"password123"}' \ | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['access_token'])") # 2. Crea una API key permanente TOKEN=$(curl -s -X POST https://insights.perseodesign.com/api/v1/tokens \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{"name":"Script CI","scopes":["read","scan","export"]}' \ | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['token'])") echo "Salva questo token: $TOKEN" # 3. Avvia una scansione SCAN_ID=$(curl -s -X POST https://insights.perseodesign.com/api/v1/scans \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","mode":"single"}' \ | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['scan_id'])") # 4. Polling finche' completo while true; do RESULT=$(curl -s -H "Authorization: Bearer $TOKEN" \ "https://insights.perseodesign.com/api/v1/scans/$SCAN_ID") STATUS=$(echo $RESULT | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['status'])") echo "Status: $STATUS" [ "$STATUS" != "running" ] && break sleep 3 done # 5. Esporta in CSV curl -s -H "Authorization: Bearer $TOKEN" \ "https://insights.perseodesign.com/api/v1/scans/127/export/csv" \ -o "report_$(date +%Y%m%d).csv"

Python: monitoring di una lista di siti

import time import requests API_BASE = "https://insights.perseodesign.com/api/v1" TOKEN = "sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} SITES = ["https://example.com", "https://myblog.com"] def scan_site(url): resp = requests.post(f"{API_BASE}/scans", json={"url": url, "mode": "single"}, headers=HEADERS) resp.raise_for_status() scan_id = resp.json()["data"]["scan_id"] while True: time.sleep(3) data = requests.get(f"{API_BASE}/scans/{scan_id}", headers=HEADERS).json()["data"] if data["status"] == "complete": return data.get("result", {}) elif data["status"] in ("error", "stopped"): raise RuntimeError(data.get("error")) for site in SITES: result = scan_site(site) g = result.get("googlebot", {}) print(f"{site}: SEO={g.get('seo_score')} Errori={len(g.get('errors',[]))}")

JavaScript/Node.js: scansione sitemap

const fetch = require('node-fetch'); const API_BASE = 'https://insights.perseodesign.com/api/v1'; const TOKEN = 'sk_live_xxxx'; const headers = { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }; async function scanSitemap(url) { const { data } = await (await fetch(`${API_BASE}/scans`, { method: 'POST', headers, body: JSON.stringify({ url, mode: 'sitemap' }) })).json(); let result; while (true) { await new Promise(r => setTimeout(r, 3000)); result = (await (await fetch(`${API_BASE}/scans/${data.scan_id}`, { headers })).json()).data; if (result.status !== 'running') break; } return result; } scanSitemap('https://myblog.com/sitemap.xml').then(r => console.log(`Completata! ${r.result?.length} URL analizzati`) );