Documentation API
Intégrez SiteRadar dans vos applications avec notre API REST complète.
Introduction
L'API SiteRadar permet d'automatiser la gestion de vos sites web et de leurs audits SEO. Elle est disponible pour les abonnés PRO.
Base URL de l'API :
https://siteradar.cloud/api/v1
Toutes les requêtes doivent utiliser HTTPS. Les requêtes HTTP seront rejetées.
Authentification
L'API utilise des clés API pour l'authentification. Vous pouvez créer et gérer vos clés dans les paramètres API.
Incluez votre clé API dans le header X-API-Key de chaque requête :
curl -X GET "https://siteradar.cloud/api/v1/sites" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
$ch = curl_init('https://siteradar.cloud/api/v1/sites');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx',
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
$data = json_decode($response, true);
const response = await fetch('https://siteradar.cloud/api/v1/sites', {
headers: {
'X-API-Key': 'sr_live_xxxxxxxxxxxxxxxxxxxx'
}
});
const data = await response.json();
import requests
response = requests.get(
'https://siteradar.cloud/api/v1/sites',
headers={'X-API-Key': 'sr_live_xxxxxxxxxxxxxxxxxxxx'}
)
data = response.json()
Codes d'erreur
L'API utilise les codes HTTP standard pour indiquer le succès ou l'échec d'une requête.
| Code | Signification |
|---|---|
200 | Succès |
201 | Ressource créée |
400 | Requête invalide (paramètres manquants ou incorrects) |
401 | Non authentifié (clé API manquante ou invalide) |
403 | Accès refusé (quota dépassé ou ressource non autorisée) |
404 | Ressource non trouvée |
429 | Trop de requêtes (rate limiting) |
500 | Erreur serveur |
Format des erreurs
{
"success": false,
"error": {
"code": "INVALID_PARAMETER",
"message": "Le paramètre 'url' est requis"
}
}
Limites de requêtes
Les limites de requêtes sont incluses dans les headers de chaque réponse :
| Header | Description |
|---|---|
X-RateLimit-Limit | Nombre maximum de requêtes par heure |
X-RateLimit-Remaining | Requêtes restantes |
X-RateLimit-Reset | Timestamp de réinitialisation |
Compte
Informations sur votre compte et votre utilisation
/account/me
Récupère les informations de votre compte.
Réponse
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe",
"company": "Acme Inc",
"preferredLocale": "fr",
"emailVerified": true,
"createdAt": "2024-01-15T10:30:00+00:00"
}
}
/account/usage
Récupère les statistiques d'utilisation et les quotas de votre compte.
Réponse
{
"success": true,
"data": {
"plan": "pro",
"usage": {
"websites": {
"used": 12,
"limit": 50,
"remaining": 38
},
"scansThisMonth": {
"used": 45,
"limit": -1,
"remaining": -1
},
"apiRequests": {
"total": 1234
}
},
"features": {
"api": true,
"whiteLabel": true,
"webhooks": true,
"scheduledScans": true,
"teamSharing": true
},
"subscription": {
"status": "active",
"currentPeriodEnd": "2024-02-15T00:00:00+00:00"
}
}
}
Sites
Gérez vos sites web
/sites
Liste tous vos sites.
Exemple de requête
curl -X GET "https://siteradar.cloud/api/v1/sites" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
Réponse
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com",
"domain": "example.com",
"displayName": "Mon Site",
"verified": true,
"createdAt": "2024-01-10T08:00:00+00:00",
"lastScanAt": "2024-01-20T14:30:00+00:00",
"lastScore": 85
}
],
"meta": {
"total": 1
}
}
/sites
Ajoute un nouveau site à surveiller.
Paramètres
| Paramètre | Type | Requis | Description |
|---|---|---|---|
url | string | Oui | URL complète du site (https://) |
name | string | Non | Nom d'affichage du site |
Exemple de requête
curl -X POST "https://siteradar.cloud/api/v1/sites" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"name": "Mon Nouveau Site"
}'
Réponse
{
"success": true,
"data": {
"id": "660e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com",
"domain": "example.com",
"displayName": "Mon Nouveau Site",
"verified": false,
"verificationToken": "siteradar-verify-abc123xyz",
"createdAt": "2024-01-20T15:00:00+00:00"
}
}
/sites/{id}/dns-record
Récupère l'enregistrement DNS TXT à ajouter pour vérifier le site.
Réponse
{
"success": true,
"data": {
"type": "TXT",
"host": "_siteradar",
"value": "siteradar-verify-abc123xyz",
"fullRecord": "_siteradar.example.com TXT siteradar-verify-abc123xyz"
}
}
/sites/{id}/verify
Lance la vérification de propriété du site.
Paramètres
| Paramètre | Type | Description |
|---|---|---|
method | string | dns ou file (défaut: dns) |
Réponse (succès)
{
"success": true,
"data": {
"verified": true,
"message": "Site vérifié avec succès"
}
}
Réponse (échec)
{
"success": false,
"error": {
"code": "VERIFICATION_FAILED",
"message": "Enregistrement DNS non trouvé"
}
}
/sites/{id}
Supprime un site et toutes ses données.
Réponse
{
"success": true,
"data": {
"message": "Site supprimé"
}
}
Scans
Lancez et consultez les audits de vos sites
/sites/{id}/scans
Lance un nouveau scan sur le site. Le site doit être vérifié.
Exemple de requête
curl -X POST "https://siteradar.cloud/api/v1/sites/550e8400.../scans" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
Réponse
{
"success": true,
"data": {
"id": "770e8400-e29b-41d4-a716-446655440000",
"status": "running",
"startedAt": "2024-01-20T15:30:00+00:00",
"pagesCrawled": 0,
"issuesCount": 0
}
}
Utilisez les webhooks pour être notifié quand le scan est terminé, plutôt que de faire du polling.
/scans/{id}
Récupère les résultats complets d'un scan.
Réponse
{
"success": true,
"data": {
"id": "770e8400-e29b-41d4-a716-446655440000",
"website": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com",
"displayName": "Mon Site"
},
"status": "completed",
"trigger": "api",
"startedAt": "2024-01-20T15:30:00+00:00",
"completedAt": "2024-01-20T15:35:00+00:00",
"duration": 300,
"pagesCrawled": 42,
"issuesCount": 15,
"score": {
"global": 78,
"seo": 82,
"performance": 71,
"accessibility": 85,
"security": 90,
"mobile": 68
},
"summary": {
"critical": 2,
"important": 5,
"moderate": 6,
"minor": 2
}
}
}
/scans/{id}/issues
Liste tous les problèmes détectés lors du scan.
Paramètres de requête (optionnels)
| Paramètre | Type | Description |
|---|---|---|
category | string | Filtrer par catégorie (seo, performance, accessibility, security, mobile) |
severity | string | Filtrer par sévérité (critical, important, moderate, minor) |
page | int | Numéro de page (défaut: 1) |
limit | int | Nombre de résultats par page (défaut: 50, max: 100) |
Exemple de requête
curl -X GET "https://siteradar.cloud/api/v1/scans/770e.../issues?category=seo&severity=critical" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
Réponse
{
"success": true,
"data": [
{
"id": "880e8400-e29b-41d4-a716-446655440000",
"category": "seo",
"severity": "critical",
"issueKey": "missing_title",
"message": "La balise title est manquante",
"url": "https://example.com/page",
"context": {
"recommendation": "Ajoutez une balise unique et descriptive"
}
}
],
"meta": {
"total": 15,
"page": 1,
"limit": 50,
"pages": 1
}
}
/scans/{id}/pages
Liste toutes les pages crawlées lors du scan.
Réponse
{
"success": true,
"data": [
{
"id": "990e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com/",
"title": "Accueil - Mon Site",
"statusCode": 200,
"responseTimeMs": 245,
"contentSizeBytes": 52480,
"depth": 0,
"issuesCount": 3
}
],
"meta": {
"total": 42,
"page": 1,
"limit": 50,
"pages": 1
}
}
/scans/{id}/pages/{pageId}
Récupère les détails complets d'une page crawlée.
Réponse
{
"success": true,
"data": {
"id": "990e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com/",
"title": "Accueil - Mon Site",
"metaDescription": "Description de mon site...",
"statusCode": 200,
"responseTimeMs": 245,
"contentSizeBytes": 52480,
"contentType": "text/html",
"depth": 0,
"headings": {
"h1": ["Mon Site"],
"h2": ["Services", "Contact"],
"h3": []
},
"images": [
{"src": "/images/logo.png", "alt": "Logo", "width": 200, "height": 50}
],
"links": {
"internal": 15,
"external": 3
},
"issues": [
{
"category": "seo",
"severity": "moderate",
"issueKey": "meta_description_too_short",
"message": "La méta description est trop courte"
}
]
}
}
Exports
Exportez les résultats de vos scans
/scans/{id}/export/pdf
Génère un rapport PDF du scan.
Paramètres optionnels
| Paramètre | Type | Description |
|---|---|---|
whiteLabel | boolean | Utiliser les paramètres marque blanche (si configurés) |
Exemple de requête
curl -X GET "https://siteradar.cloud/api/v1/scans/770e.../export/pdf?whiteLabel=true" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx" \
-o rapport.pdf
Content-Type: application/pdf
La réponse est directement le fichier PDF binaire.
/scans/{id}/export/csv
Exporte les données du scan au format CSV.
Paramètres optionnels
| Paramètre | Type | Description |
|---|---|---|
type | string | detailed (défaut) : Export complet avec pages | issues : Seulement les problèmes |
Exemple de requête
curl -X GET "https://siteradar.cloud/api/v1/scans/770e.../export/csv?type=issues" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx" \
-o issues.csv
Format du CSV (type=issues)
URL,Catégorie,Sévérité,Problème,Message
https://example.com/,seo,critical,missing_title,La balise title est manquante
https://example.com/contact,performance,moderate,large_image,Image trop volumineuse
Webhooks
Gérez vos webhooks et recevez des notifications en temps réel
Les webhooks vous permettent de recevoir des notifications automatiques quand certains événements se produisent. Vous pouvez les gérer via l'API ou dans les paramètres API.
/webhooks
Liste tous vos webhooks configurés.
Exemple de requête
curl -X GET "https://siteradar.cloud/api/v1/webhooks" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
Réponse
{
"success": true,
"data": [
{
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"name": "Mon Webhook CI/CD",
"url": "https://my-app.com/webhooks/siteradar",
"events": ["scan.completed", "scan.failed"],
"active": true,
"createdAt": "2024-01-15T10:00:00+00:00",
"lastTriggeredAt": "2024-01-20T14:30:00+00:00",
"successCount": 42,
"failureCount": 1,
"lastError": null,
"secretPrefix": "whsec_xxxx..."
}
]
}
/webhooks
Crée un nouveau webhook.
Paramètres
| Paramètre | Type | Requis | Description |
|---|---|---|---|
name | string | Oui | Nom du webhook |
url | string | Oui | URL HTTPS du endpoint |
events | array | Oui | Liste des événements à écouter |
Exemple de requête
curl -X POST "https://siteradar.cloud/api/v1/webhooks" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Mon Webhook CI/CD",
"url": "https://my-app.com/webhooks/siteradar",
"events": ["scan.completed", "scan.failed"]
}'
Réponse
{
"success": true,
"data": {
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"name": "Mon Webhook CI/CD",
"url": "https://my-app.com/webhooks/siteradar",
"events": ["scan.completed", "scan.failed"],
"active": true,
"createdAt": "2024-01-20T15:00:00+00:00",
"secret": "whsec_abc123xyz789..."
}
}
Important : Le secret n'est retourné qu'à la création. Conservez-le précieusement pour vérifier les signatures.
/webhooks/{id}
Récupère les détails d'un webhook.
Réponse
{
"success": true,
"data": {
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"name": "Mon Webhook CI/CD",
"url": "https://my-app.com/webhooks/siteradar",
"events": ["scan.completed", "scan.failed"],
"active": true,
"createdAt": "2024-01-15T10:00:00+00:00",
"lastTriggeredAt": "2024-01-20T14:30:00+00:00",
"successCount": 42,
"failureCount": 1,
"lastError": null,
"secret": "whsec_abc123xyz789..."
}
}
/webhooks/{id}
Met à jour un webhook existant. Seuls les champs fournis seront modifiés.
Paramètres (tous optionnels)
| Paramètre | Type | Description |
|---|---|---|
name | string | Nouveau nom du webhook |
url | string | Nouvelle URL du endpoint |
events | array | Nouvelle liste d'événements |
active | boolean | Activer/désactiver le webhook |
Exemple de requête
curl -X PUT "https://siteradar.cloud/api/v1/webhooks/aa0e8400..." \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"active": false,
"events": ["scan.completed"]
}'
Réponse
{
"success": true,
"data": {
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"name": "Mon Webhook CI/CD",
"url": "https://my-app.com/webhooks/siteradar",
"events": ["scan.completed"],
"active": false,
"...": "..."
}
}
/webhooks/{id}
Supprime un webhook.
Exemple de requête
curl -X DELETE "https://siteradar.cloud/api/v1/webhooks/aa0e8400..." \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
Réponse
HTTP 204 No Content
/webhooks/{id}/regenerate-secret
Régénère le secret d'un webhook. L'ancien secret sera immédiatement invalidé.
Exemple de requête
curl -X POST "https://siteradar.cloud/api/v1/webhooks/aa0e8400.../regenerate-secret" \
-H "X-API-Key: sr_live_xxxxxxxxxxxxxxxxxxxx"
Réponse
{
"success": true,
"data": {
"secret": "whsec_newSecret123...",
"message": "Secret regenerated successfully"
}
}
Attention : Mettez à jour votre endpoint immédiatement après cette opération, sinon les vérifications de signature échoueront.
/webhooks/events
Liste tous les événements disponibles pour les webhooks.
Réponse
{
"success": true,
"data": {
"events": [
{"name": "scan.started", "description": "Triggered when a scan starts"},
{"name": "scan.completed", "description": "Triggered when a scan completes successfully"},
{"name": "scan.failed", "description": "Triggered when a scan fails"},
{"name": "site.verified", "description": "Triggered when a site is verified"}
]
}
}
Réception des webhooks
Cette section explique comment recevoir et traiter les webhooks sur votre serveur.
Événements disponibles
| Événement | Description |
|---|---|
scan.started | Un scan a démarré |
scan.completed | Un scan s'est terminé avec succès |
scan.failed | Un scan a échoué |
site.verified | Un site a été vérifié |
Format des webhooks
Chaque webhook est envoyé en POST avec un corps JSON :
{
"event": "scan.completed",
"timestamp": "2024-01-20T15:35:00+00:00",
"data": {
"scan": {
"id": "770e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"pagesCrawled": 42,
"issuesCount": 15,
"score": 78
},
"website": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com",
"displayName": "Mon Site"
}
}
}
Vérification de la signature
Chaque webhook inclut des headers de sécurité pour vérifier son authenticité :
| Header | Description |
|---|---|
X-SiteRadar-Signature | Signature HMAC SHA256 |
X-SiteRadar-Timestamp | Timestamp Unix de l'envoi |
X-SiteRadar-Event | Type d'événement |
Exemples de vérification
<?php
$secret = 'votre_secret_webhook';
$payload = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_SITERADAR_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_SITERADAR_SIGNATURE'] ?? '';
// Vérifier que le timestamp n'est pas trop ancien (5 minutes)
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(400);
die('Timestamp expired');
}
// Calculer la signature attendue
$signedPayload = "{$timestamp}.{$payload}";
$expected = 'v1=' . hash_hmac('sha256', $signedPayload, $secret);
// Comparer de manière sécurisée
if (!hash_equals($expected, $signature)) {
http_response_code(401);
die('Invalid signature');
}
// Traiter l'événement
$event = json_decode($payload, true);
// ... votre logique ici
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const payload = JSON.stringify(req.body);
const timestamp = req.headers['x-siteradar-timestamp'];
const signature = req.headers['x-siteradar-signature'];
// Vérifier le timestamp
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
throw new Error('Timestamp expired');
}
// Calculer la signature
const signedPayload = `${timestamp}.${payload}`;
const expected = 'v1=' + crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Comparer de manière sécurisée
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
throw new Error('Invalid signature');
}
return req.body;
}
import hmac
import hashlib
import time
def verify_webhook(payload: bytes, timestamp: str, signature: str, secret: str) -> bool:
# Vérifier le timestamp
if abs(time.time() - int(timestamp)) > 300:
raise ValueError('Timestamp expired')
# Calculer la signature
signed_payload = f"{timestamp}.{payload.decode('utf-8')}"
expected = 'v1=' + hmac.new(
secret.encode('utf-8'),
signed_payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
# Comparer de manière sécurisée
if not hmac.compare_digest(expected, signature):
raise ValueError('Invalid signature')
return True
Bonnes pratiques
- Répondez toujours avec un code 200 dans les 30 secondes
- Traitez les webhooks de manière asynchrone si le traitement est long
- Implémentez une idempotence pour gérer les duplications éventuelles
- Conservez le secret de manière sécurisée (variable d'environnement)
Besoin d'aide ?
Si vous avez des questions sur l'API ou rencontrez des problèmes, n'hésitez pas à nous contacter.