API v1 — plan Agence

Pilotez vos scans par API

Lisez le dernier scan d'un domaine, déclenchez-en de nouveaux et recevez un webhook signé à chaque scan terminé.

1. Authentification

Créez une clé depuis Dashboard > Paramètres. Envoyez-la en header Bearer. Seuls les comptes au plan Agence actif sont autorisés (401 sinon, clé jamais stockée en clair, hash SHA-256 côté serveur).

curl -H "Authorization: Bearer VOTRE_CLE" \
  "https://conformergpd.fr/api/v1/scans?domain=example.fr"

2. Lire le dernier scan

GET /api/v1/scans?domain= — le domaine doit appartenir à votre compte, sinon 404. Réponse mise en cache : jamais (no-store).

{
  "domain": "example.fr",
  "url": "https://example.fr/",
  "scannedAt": "2026-09-13T08:12:00.000Z",
  "complianceScore": 82,
  "categoryScores": { "cookies": 90, "consentement": 74 },
  "summary": {
    "totalCookies": 14,
    "thirdPartyCookies": 6,
    "trackersFound": 3,
    "hasCookieBanner": true,
    "hasPrivacyPolicy": true,
    "hasMentionsLegales": true,
    "cms": "wordpress",
    "pagesScanned": 4,
    "partialScan": false,
    "durationMs": 9213
  },
  "issues": [ /* constats complets, remediation incluse */ ]
}

3. Déclencher un scan

POST /api/v1/scans avec { domain } — répond 202 immédiatement, le scan tourne en arrière-plan (budget profondeur maximal), puis notifie vos webhooks. Relisez le résultat via GET.

curl -X POST -H "Authorization: Bearer VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.fr"}' \
  "https://conformergpd.fr/api/v1/scans"

# → 202 { "scanId": "…", "status": "running", "domain": "example.fr" }

4. Webhooks

Configurez vos URLs depuis la page d'un site (plan Agence). À chaque scan terminé : POST JSON scan.completed (siteId, scanId, domain, score, issuesCount, scannedAt), headers x-crgpd-event et x-crgpd-signature (HMAC-SHA256 hexadécimal du corps brut avec votre secret, affiché une seule fois à la création). Seules les URLs https publiques sont acceptées.

import { createHmac, timingSafeEqual } from "node:crypto";

function isValid(secret: string, rawBody: string, signature: string): boolean {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

5. Erreurs

CodeSignification
401Clé absente, invalide, révoquée — ou plan non-Agence / inactif
404Domaine inconnu de votre compte, ou aucun scan terminé
400Paramètre { domain } manquant ou invalide
500Création du scan impossible, réessayez