API REST Rankscale
Rankscale est un outil de suivi de visibilité de marque par IA. Il interroge divers modèles d'IA (ChatGPT, Gemini, Claude, Perplexity, etc.) avec les termes de recherche suivis par l'utilisateur, analyse les réponses et rapporte à quelle fréquence, où et avec quelle favorabilité les marques suivies sont mentionnées.
Cette compétence appelle directement l'API REST afin que l'utilisateur (un professionnel du référencement, pas un développeur) puisse extraire des données pour des rapports, des graphiques et des analyses personnalisées sans cliquer sur le tableau de bord.
Configuration
- Clé API : Lue depuis la variable d'environnement
RANKSCALE_API_KEY. Le format de la clé estrk_<hash>_<workspaceId>— le suffixe est un identifiant d'espace de travail, pas un ID de marque, donc une seule clé atteint chaque marque dans son espace de travail (particularités §15). Si elle n'est pas définie, demandez à l'utilisateur de la définir une fois : PowerShellsetx RANKSCALE_API_KEY "rk_..."(un nouveau shell est nécessaire pour prendre effet) ou passez-la par session avec$env:RANKSCALE_API_KEY = "rk_...". Ne jamais afficher la clé dans les réponses ni l'écrire dans des fichiers. - URL de base :
https://rankscale.ai(note : pas de préfixe/api— le chemin est/v1/...directement sur le domaine marketing). - En-tête d'authentification :
Authorization: Bearer $RANKSCALE_API_KEY. - Limite de débit : 200 requêtes par minute par clé API. La réponse contient
X-RateLimit-Limit,X-RateLimit-RemainingetX-RateLimit-Reset(secondes jusqu'à la réinitialisation de la fenêtre) — lisez-les aveccurl -isi vous effectuez un traitement par lots. Mettez en cache les réponses des rapports pendant 5 à 10 minutes lorsque cela est possible. - Outils disponibles :
curlpour les requêtes. Pour l'analyse JSON, utilisez ce que l'environnement fournit —node -e "...",jq, oupython -m json.tool. Vérifiez ce qui se trouve dans le PATH avant de supposer ; ne dépendez pas exclusivement d'un seul d'entre eux. - Syntaxe du shell : les exemples ci-dessous utilisent l'expansion de variables de style bash (
$RANKSCALE_API_KEY). Sur Windows PowerShell, cela devient$env:RANKSCALE_API_KEY. Choisissez le shell que vous appelez — les deux fonctionnent, mais faites attention à la syntaxe.
Modèle d'appel
Chaque point de terminaison renvoie {success: true, data: {...}} en cas de succès, ou {success: false, error: {code, message, details}} en cas d'échec. Vérifiez toujours .success avant de lire .data.
Vérifiez aussi warnings. Une réponse réussie peut comporter une troisième clé de niveau supérieur, warnings[], listant les champs de requête que l'API n'a pas reconnus et ignorés — souvent avec une suggestion ("Champ non reconnu 'startDate' ignoré. Vouliez-vous dire 'isoStartDate' ? …"). Il est absent lorsque la requête est propre, donc if (json.warnings) est un garde-fou fiable. Un avertissement signifie que les chiffres répondent à une question différente de celle posée — l'API revient aux valeurs par défaut pour le champ ignoré. Signalez-le à l'utilisateur au lieu de l'ignorer ; c'est le moyen le moins coûteux de détecter le piège du camelCase (particularités §1).
Enregistrez les réponses JSON brutes dans un fichier à côté du travail de l'utilisateur (typiquement Rankscale/<endpoint>_<contexte>.json) afin qu'elles puissent être ré-analysées sans rappeler l'API. Présentez à l'utilisateur un résumé propre, pas le JSON brut, sauf s'il le demande.
Efficacité des tokens — le levier le plus important. Pour tout ce qui est volumineux (multi-sujet, multi-moteur, historique complet, ou /search-terms-report avec includeAnswerTexts), écrivez la réponse directement sur le disque avec -o et extrayez uniquement les valeurs dont vous avez besoin avec node -e. Ne lisez pas les charges utiles /report entières dans le contexte — un rapport filtré fait environ 40–50 Ko et un balayage de 7 sujets fait ~300 Ko. L'extraction de scalaires/séries côté client maintient cela hors contexte et, pour les extractions en masse, réduit approximativement de moitié l'utilisation des tokens par rapport à la lecture des charges utiles en ligne. (Pour une seule mesure étroite, la surcharge n'en vaut pas la peine — lisez simplement la petite réponse.)
Les tailles de charge utile sont très inégales — planifiez en fonction. Mesurée sur une seule marque :
| Point de terminaison | Fenêtre | Taille |
|---|---|---|
/report (filtré) | 30j | ~40–50 Ko |
/report (filtré) | 1 mois calendaire | ~105–110 Ko |
/citations | 3m | ~3.9 Mo |
/citations uncapped: true | 1 mois calendaire | ~4.4–5.7 Mo |
/sentiment | 30j | ~9 Mo |
/sentiment | 3m | ~17 Mo |
La taille n'évolue pas avec la longueur de la fenêtre — uncapped: true importe bien plus. Un seul mois sans limite est revenu plus gros qu'une extraction plafonnée de trois mois, donc n'extrapolez pas une taille d'un mois à partir de la ligne 3m.
/sentiment et /citations ne sont jamais sûrs à lire en ligne — utilisez toujours -o vers un fichier et extrayez. Pour des appels aussi lourds, capturez aussi le statut HTTP (curl -w '%{http_code}'), car un 502 transitoire arrive sous forme de corps HTML qui ressemble à un chemin cassé mais nécessite juste une nouvelle tentative (particularités §6).
# Bash (Git Bash / WSL / macOS / Linux)
curl -s -H "Authorization: Bearer $RANKSCALE_API_KEY" \
"https://rankscale.ai/v1/metrics/brands" \
-o brands.json
curl -s -X POST -H "Authorization: Bearer $RANKSCALE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"brandId":"<id>"}' \
"https://rankscale.ai/v1/metrics/report" \
-o report.json
# Équivalent PowerShell
curl.exe -s -H "Authorization: Bearer $env:RANKSCALE_API_KEY" `
"https://rankscale.ai/v1/metrics/brands" `
-o brands.json
curl.exe -s -X POST -H "Authorization: Bearer $env:RANKSCALE_API_KEY" `
-H "Content-Type: application/json" `
-d '{\"brandId\":\"<id>\"}' `
"https://rankscale.ai/v1/metrics/report" `
-o report.json
Notez dans PowerShell : utilisez curl.exe (l'alias curl pointe vers Invoke-WebRequest, qui se comporte différemment), échappez les guillemets intérieurs dans les corps JSON -d avec \", et utilisez l'accent grave ` pour la continuation de ligne. Invoke-RestMethod fonctionne aussi et analyse JSON automatiquement, mais la forme curl maintient les réponses cohérentes entre les shells.
L'inventaire complet des points de terminaison et les formes de requêtes se trouvent dans references/endpoints.md. Lisez-le avant tout appel dont vous n'êtes pas sûr. Les surprises et les pièges sont dans references/quirks.md — lisez-le avant de rapporter des métriques à l'utilisateur, car plusieurs d'entre eux affectent la façon dont les chiffres doivent être interprétés.
Hors de portée : l'API des liens de partage. Rankscale publie une deuxième API REST pour les liens de partage de tableaux de bord publics. Elle utilise une clé différente (Paramètres → Partage, pas Paramètres → Intégrations), donc RANKSCALE_API_KEY ne s'authentifiera pas auprès d'elle. Si l'utilisateur demande à créer ou révoquer un lien de partage, dites qu'il s'agit d'une API séparée que cette compétence ne couvre pas — ne devinez pas ses chemins.
Recettes de workflow
1. Identifier la marque
La plupart des points de terminaison de rapport ont besoin d'un brandId. Lorsque l'utilisateur nomme une marque ("affiche-moi les métriques d'Acme"), résolvez d'abord l'ID :
- Si
Rankscale/brands.jsonexiste dans le répertoire de travail de l'utilisateur, lisez-le. - Sinon, appelez
GET /v1/metrics/brandset enregistrez le résultat. - Faites correspondre le nom de la marque de l'utilisateur avec
brands[].name(insensible à la casse) et avecbrands[].brandInfo.names(alias). Si plusieurs correspondances, demandez à l'utilisateur de lever l'ambiguïté.
2. Extraire les métriques pour une marque sur une fenêtre
L'utilisateur demande presque toujours une fenêtre de temps. Utilisez timeFrame (camelCase, F majuscule — l'API ignore silencieusement toute autre orthographe) avec l'un de ces préréglages documentés : 24h, 7d, 30d, 3m, 1y. Associez-le à aggregation (hourly, daily, weekly, ou monthly) pour la taille du compartiment. Pour les fenêtres personnalisées, utilisez isoStartDate + isoEndDate (chaînes de date ISO appariées) ; celles-ci remplacent timeFrame.
{
"brandId": "<id>",
"timeFrame": "30d",
"aggregation": "daily",
"includeNotFoundExecutions": true
}
Filtres de rapport optionnels (tous acceptent une seule chaîne, un tableau pour OU-dans-le-champ, ou "all" pour aucun filtre ; les filtres se combinent avec ET entre les champs) :
selectedTopic— ID de sujet, nom de sujet,_orphaned, ou tableauselectedTags— tag,__UNTAGGED__, ou tableauselectedEngine— ID de moteur (préféré — voirreferences/endpoints.mdpour le catalogue) ou nom convivialselectedQuery— chaîne de requête de terme de recherche exacte ou tableausearchTermId— ID de terme de recherche uniqueperiodOffset— entier, décale la fenêtre prédéfinie de N périodes en arrière (0 = actuelle, 1 = précédente, …)userTimezone— fuseau horaire IANA commeEurope/Parispour les limites de jour locales de l'utilisateurincludeNotFoundExecutions— booléen, contrôle si les exécutions "marque non trouvée dans la réponse" comptent dans les métriques (voir quirks.md)
Lisez la réponse à partir de data.ownBrandMetrics.historicalData.<aggregation> (par ex. .daily lorsque vous avez demandé aggregation: "daily"). Chaque tableau de compartiments — visibilityScore, sentiment, mentions, sources, citations, citationCounts, avgPosition, detectionRate, top3, brandNotFound — s'exécute en parallèle avec timestamps.
Trois séries temporelles parallèles l'accompagnent :
data.ownBrandMetrics.topicMetricsData.<aggregation>— par sujetdata.ownBrandMetrics.engineMetricsData.<aggregation>— par moteur ; non documenté en amont, et généralement la coupe la plus précieuse lorsqu'une fenêtre d'agrégat semble plate, car les mouvements au niveau du moteur s'annulent dans le total (particularités §25)data.competitorTimeSeriesData.<aggregation>— par concurrent, marque propre exclue (particularités §16)
brandNotFound[] est un non-signal — il indique true pour pratiquement toute marque avec une détection inférieure à 100 %. Utilisez detectionRate à la place et ne signalez jamais "marque non trouvée" à partir de l'indicateur (particularités §2).
Présentez un tableau de métriques avec ces colonnes : Date, Visibilité, Sentiment, Mentions, Citations, Position moyenne, % de détection, % Top-3. Au-dessus, affichez le résumé instantané (valeurs instantanées actuelles de ownBrandMetrics + le delta trends).
Classement de la marque (par visibilité) — vs. concurrents. Calculez-le à partir de data.competitorMetrics[] (qui inclut la marque propre, signalée isOwnBrand: true) : rang = 1 + (nombre d'entrées avec un visibilityScore strictement supérieur) — les égalités ne font pas descendre la marque. Cela reproduit le rang du tableau de bord. La réponse contient également latestRank/avgRank par entrée — ce ne sont pas des rangs. Vérifié le 2026-08-07 : ils renvoient des valeurs non entières (latestRank: 2.7, avgRank: 2.9) pour une marque dont le rang calculé était 1, donc ils suivent quelque chose de similaire à une position, pas un ordinal. Ignorez-les. Le own_brand_rank équivalent du MCP est également toujours 1 (une épingle d'affichage). La méthode de calcul par tri de visibilité ci-dessus est celle qui correspondait au tableau de bord lors des tests. Les filtres partagés (selectedEngine, selectedTopic, selectedTags, selectedQuery) fonctionnent par coupe, vous pouvez donc classer au sein d'un seul moteur, sujet, tag ou requête en réexécutant avec filtre. Notez que les entrées competitorMetrics peuvent avoir un validMetricsCount différent de celui de la marque propre (les lignes de base des concurrents utilisent une fenêtre plus large) — le classement correspond toujours à l'interface utilisateur. Recette complète — y compris le rang quotidien dans le temps et ses mises en garde — dans la recette §6 ci-dessous.
3. Analyse des citations
/v1/metrics/citations renvoie les sources (sites, articles) que les modèles d'IA citent en répondant aux termes de recherche de l'utilisateur. Utile pour comprendre quels domaines tiers influencent les réponses IA concernant une marque.
Champs clés : data.totalCitations, data.uniqueCitations (URL distinctes), data.uniqueDomains et data.citationsByDomain[] (chaque domaine). Dans chaque entrée de domaine, occurrences est le nombre ; le champ citations est le tableau d'URL, pas un nombre — donc la part de citation = occurrences / totalCitations, et les URL principales proviennent de l'aplatissement du tableau d'URL de chaque domaine et du tri par occurrences.
Chaque objet URL est {url, normalizedUrl, occurrences, engineAppearances: {<engineId>: count}, firstSeenAt, lastSeenAt, category, searchTerms[]}. engineAppearances est la seule répartition des citations par moteur dans l'API — additionnez-la sur les URL d'un domaine pour répondre à "quels moteurs citent notre site". firstSeenAt/lastSeenAt sont le seul écho de la fenêtre que vous avez réellement obtenue. Normalisez davantage normalizedUrl avant l'analyse au niveau de la page (elle laisse les variantes www./barre oblique finale/requête distinctes), et notez que category: "owned" signifie "le site propre d'une entreprise", pas détenu par la marque suivie — les concurrents l'ont aussi. Voir particularités.md §13b. data.domainSummary a des vues pré-découpées (topDomainsOverall, topDomainsByEngine, topDomainsByQuery, topDomainsByOwnBrandCitations, topDomainsByCompetitor) — mais celles-ci sont plafonnées (≈20/10 entrées) et topDomainsByCompetitor répertorie les domaines où un concurrent a été mentionné (inclut des sites tiers neutres comme Reddit/Booking), donc ne l'utilisez pas pour identifier les sites détenus par un concurrent. Voir particularités.md §13b.
Vérifiez les plafonds avant de considérer une liste comme complète. La réponse plafonne par défaut à 5 000 URL uniques et 50 marques. data.paginationInfo indique la vérité — citationsCapped, brandsCapped, responseTrimmed, capBypassed, maxCitations, maxBrands, totalCount vs returnedCount. Passez uncapped: true (paramètre de corps ou de requête) pour lever le plafond d'URL ; il ne lève pas le plafond de 50 marques ni le garde-fou de taille de réponse. deduplicated: true déduplique les chemins de réponse et ajoute data.searchTermsById. Si un indicateur de plafond est true, dites-le à l'utilisateur et réduisez la fenêtre ou filtrez plutôt que de présenter une liste tronquée comme l'image complète. Voir particularités.md §13c.
4. Sentiment
/v1/metrics/sentiment renvoie des agrégats de sentiment au niveau de la fenêtre plus des nuages de mots-clés pour la marque suivie et chaque concurrent — pas une série temporelle (utilisez /report's historicalData.<agg>.sentiment[] pour le sentiment dans le temps). Mêmes filtres partagés, plus deduplicated: true.
Deux tableaux avec des portées différentes : data.brandSentiments[] concerne uniquement la marque suivie ; data.companySentiments[] concerne chaque marque détectée, y compris la marque propre (isOwnBrand: true) — utilisez celui-ci pour les comparaisons de concurrents. brandSentimentsBySearchTerm[] / companySentimentsBySearchTerm[] donnent les mêmes coupes par terme de recherche.
Par entrée : avgSentiment (échelle 0–100, = totalSentimentScore / sentimentCount), sentimentCount, executionCount et positiveCount / neutralCount / negativeCount. Le sentiment est divisé par source — blocs webGrounding* (moteurs ancrés sur le web) vs trainingData*, contrôlés par les booléens hasWebGrounding / hasTrainingData, avec webGroundingSentimentByEngine[<engineId>] = {sum, count, avg} pour les scores par moteur.
Deux pièges — lisez particularités.md §19 avant de rapporter quoi que ce soit. (1) `p
[… tronqué pour la traduction]