Liste les modules disponibles (public, sans clé).
curl https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1/featuresUne seule clé crw_live_… pour interroger les 18 modules d'analyse SEO, GEO et IA de Crawlers. Modèle asynchrone par polling : vous créez un job, vous interrogez son statut, vous récupérez le résultat structuré en JSON.
L'API Crawlers expose chaque fonctionnalité de la plateforme en endpoint individuel, via un dispatcher unique. Vous postez { feature, input } sur /v1/jobs, vous récupérez un job_id, puis vous interrogez /v1/jobs/{id} jusqu'à status = "succeeded".
Base URL
https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1Pour le pipeline éditorial complet (publication CMS), voir l'API Parménion. Pour la génération de rapports B2B en marque blanche, voir l'API Marina.
Toutes les requêtes (sauf /v1/features et /health) requièrent une clé API personnelle au format crw_live_…. La clé est stockée côté Crawlers sous forme de hash SHA-256 ; elle n'est affichée qu'une seule fois à sa création.
Deux modes équivalents :
Authorization: Bearer crw_live_xxxxxxxxxxxxxxxxxxxxxxxx
# ou
x-crawlers-key: crw_live_xxxxxxxxxxxxxxxxxxxxxxxxCréation depuis votre compte → onglet API. La clé peut être révoquée à tout moment.
202 Accepted, statut queued.running dans la seconde qui suit.succeeded (champ result rempli) ou failed (champ error).Durées typiques : pagespeed 10–30 s, geo_score 20–60 s, audit_expert 1–3 min, site_crawl 2–15 min selon la taille.
Liste les modules disponibles (public, sans clé).
curl https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1/featuresCrée un job pour le module choisi. Débite 0,10 € du wallet (atomique : si le solde est insuffisant, le job est marqué failed et aucun débit n'est appliqué).
Requête
curl -X POST https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1/jobs \
-H "Authorization: Bearer crw_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"feature": "geo_score",
"input": { "url": "https://example.com/blog/article" }
}'202 Accepted — job créé, débit effectué
Header Location: /v1/jobs/<id>. Le client poll poll_url.
{
"id": "5d6e7f12-...-9a0b",
"feature": "geo_score",
"status": "queued",
"created_at": "2026-05-26T10:00:00Z",
"cost_cents": 10,
"poll_url": "/v1/jobs/5d6e7f12-...-9a0b"
}400 Bad Request — payload invalide
// JSON malformé
{ "error": "invalid_json" }
// feature absent
{ "error": "missing_field", "field": "feature" }
// feature inconnue
{ "error": "unknown_feature", "feature": "foo", "see": "/v1/features" }
// input n'est pas un objet
{ "error": "invalid_input", "expected": "object" }401 Unauthorized — authentification
// Aucune clé fournie
{ "error": "missing_api_key", "docs": "/docs/api/crawlers#authentication" }
// Clé inconnue, révoquée ou mal formée
{ "error": "invalid_api_key", "docs": "/docs/api/crawlers#authentication" }402 Payment Required — solde wallet insuffisant
Le job est créé puis marqué failed avec error.message = "insufficient_balance". Aucun débit n'a lieu. Rechargez sur /developers/profil?tab=facturation.
{
"error": "insufficient_balance",
"message": "Recharge ton wallet sur /developers/profil?tab=facturation",
"job_id": "5d6e7f12-...-9a0b"
}500 Internal Server Error — erreur serveur
// Erreur base de données (insert job)
{ "error": "db_error", "detail": "<message Postgres>" }
// Exception non gérée dans le router
{ "error": "internal_error", "message": "<message>" }À retraiter avec backoff exponentiel (1 s, 2 s, 4 s, max 5 tentatives).
Récupère l'état d'un job et son résultat si status = "succeeded".
{
"id": "5d6e7f12-...-9a0b",
"feature": "geo_score",
"status": "succeeded",
"input": { "url": "https://example.com/blog/article" },
"result": {
"score": 78,
"breakdown": { "machine_readability": 82, "fan_out": 71, "citation": 80 }
},
"error": null,
"created_at": "2026-05-26T10:00:00Z",
"started_at": "2026-05-26T10:00:01Z",
"completed_at": "2026-05-26T10:00:42Z"
}Liste vos derniers jobs (paramètre ?limit=20, max 100).
Annule un job queued ou running. Renvoie 409 si le job est déjà terminé.
Chaque module est appelé via { "feature": "<id>", "input": { … } }.
| ID | Module | Input attendu | Statut |
|---|---|---|---|
| audit_expert | Audit Expert (168 critères) Audit technique, sémantique et E-E-A-T sur 168 critères. | url: string (https) | preview |
| machine_layer | Machine Layer Scanner Lisibilité bots IA, JSON-LD, robots.txt, sitemap, fan-out. | url: string | preview |
| eeat | Score E-E-A-T Expertise, autorité, fiabilité (scoring v3). | url: string | preview |
| site_crawl | Crawl de site Crawl BFS d'un domaine (3 niveaux de profondeur max). | domain: string depth: number? limit: number? | preview |
| pagespeed | PageSpeed Insights Mobile + desktop, Core Web Vitals (LCP, CLS, INP). | url: string | preview |
| audit_matrix | Matrice d'audit Multi-pages, export CSV-ready. | domain: string urls: string[]? | preview |
| semantic_audit | Audit sémantique Champ lexical, entités, alignement intention (Lexical Footprint v2). | url: string keyword: string? | preview |
| cocoon | Cocoon sémantique 3D Clusters, cannibalisation, profondeur, liens internes. | domain: string | preview |
| content_architect | Content Architect Recommandation éditoriale en 4 étages (brief / stratège / rédacteur / tonalisateur). | domain: string topic: string target_audience: string? | preview |
| autopilot_status | Autopilote (statut) Lecture du statut Parménion pour un domaine. | domain: string | preview |
| conversion_optimizer | Conversion Optimizer CTA, friction, GA4 behavioral metrics. | url: string | preview |
| social_hub | Social Hub Génère des variations sociales depuis un article. | url: string platforms: string[]? | preview |
| geo_score | Score GEO Generative Engine Optimization (lisibilité par moteurs IA). | url: string | preview |
| llm_visibility | Visibilité LLM Présence d'une marque dans ChatGPT, Perplexity, Gemini, Claude. | brand: string queries: string[] | preview |
| ai_bots_analysis | Analyse Bots IA Hits bots IA (GPTBot, ClaudeBot, PerplexityBot, …) sur 30 jours. | domain: string | preview |
| observatory | Observatoire sectoriel Benchmarks (positions moyennes, mix bots, IAS) par secteur. | sector: string | preview |
| serp_ranking | Ranking SERP Positions multi-providers (DataForSEO + SerpAPI + Serper + Bright Data). | keyword: string domain: string? location: string? | preview |
| competitors | Concurrence Audit concurrentiel (SEO + GEO + SERP delta) sur 1 à 3 URLs. | domain: string competitors: string[] | preview |
| HTTP | Code | Description |
|---|---|---|
| 400 | missing_field | Champ obligatoire manquant (souvent feature). |
| 400 | unknown_feature | L'ID de module n'existe pas. Voir GET /v1/features. |
| 400 | invalid_input | Le champ input doit être un objet JSON. |
| 400 | invalid_json | Le corps de la requête n'est pas du JSON valide. |
| 401 | missing_api_key | Aucune clé fournie dans Authorization ou x-crawlers-key. |
| 401 | invalid_api_key | Clé inconnue, mal formée ou révoquée. |
| 402 | insufficient_balance | Solde wallet < 0,10 €. Le job est créé puis marqué failed sans débit. Rechargez sur /developers/profil?tab=facturation. |
| 404 | job_not_found | Le job n'existe pas, ou ne vous appartient pas. |
| 409 | not_cancellable | Le job est déjà terminé (succeeded/failed/cancelled). |
| 429 | rate_limited | Quota dépassé. Voir l'en-tête Retry-After. |
| 500 | internal_error | Erreur côté Crawlers. Réessayez avec backoff exponentiel. |
const KEY = process.env.CRAWLERS_API_KEY;
const BASE = "https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1";
async function run(feature, input) {
// 1. créer le job
const r = await fetch(`${BASE}/jobs`, {
method: "POST",
headers: { "Authorization": `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ feature, input }),
});
const { id } = await r.json();
// 2. polling
while (true) {
await new Promise(r => setTimeout(r, 3000));
const s = await fetch(`${BASE}/jobs/${id}`, { headers: { "Authorization": `Bearer ${KEY}` } });
const job = await s.json();
if (job.status === "succeeded") return job.result;
if (job.status === "failed") throw new Error(JSON.stringify(job.error));
}
}
const score = await run("geo_score", { url: "https://example.com/blog/article" });
console.log(score);<?php
$KEY = getenv('CRAWLERS_API_KEY');
$BASE = 'https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1';
function crawlers_run($feature, $input) {
global $KEY, $BASE;
$ch = curl_init("$BASE/jobs");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["feature" => $feature, "input" => $input]),
]);
$job = json_decode(curl_exec($ch), true); curl_close($ch);
while (true) {
sleep(3);
$ch = curl_init("$BASE/jobs/{$job['id']}");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer $KEY"]]);
$r = json_decode(curl_exec($ch), true); curl_close($ch);
if ($r['status'] === 'succeeded') return $r['result'];
if ($r['status'] === 'failed') throw new RuntimeException(json_encode($r['error']));
}
}import os, time, requests
KEY = os.environ["CRAWLERS_API_KEY"]
BASE = "https://tutlimtasnjabdfhpewu.functions.supabase.co/crawlers-api/v1"
H = {"Authorization": f"Bearer {KEY}"}
def run(feature, input):
r = requests.post(f"{BASE}/jobs", headers={**H, "Content-Type": "application/json"},
json={"feature": feature, "input": input})
job_id = r.json()["id"]
while True:
time.sleep(3)
job = requests.get(f"{BASE}/jobs/{job_id}", headers=H).json()
if job["status"] == "succeeded": return job["result"]
if job["status"] == "failed": raise RuntimeError(job["error"])
print(run("geo_score", {"url": "https://example.com/blog/article"}))Les dépassements renvoient 429 avec un en-tête Retry-After (secondes).