API Documentation
Integrate SiteRadar into your applications with our complete REST API.
Introduction
The SiteRadar API allows you to automate the management of your websites and their SEO audits. It is available for PRO subscribers.
API Base URL:
https://siteradar.cloud/api/v1
All requests must use HTTPS. HTTP requests will be rejected.
Authentication
The API uses API keys for authentication. You can create and manage your keys in the API settings.
Include your API key in the X-API-Key header of each request:
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()
Error Codes
The API uses standard HTTP codes to indicate the success or failure of a request.
| 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"
}
}
Rate Limiting
Rate limits are included in the headers of each response:
| 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 |
Account
Information about your account and usage
/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
Manage your websites
/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
Run and view audits of your 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
Export your scan results
/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
Manage your webhooks and receive real-time notifications
Webhooks allow you to receive automatic notifications when certain events occur. You can manage them via the API or in the API settings.
/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)
Need help?
If you have questions about the API or encounter issues, feel free to contact us.