Référence de l'API
Points d'accès, champs de réponse, codes de statut, limites de débit et nos engagements de stabilité.
Référence de l'API (V2)
URL de base : https://api.captchacore.eu — tous les points d'accès répondent en JSON. Si vous utilisez le widget fourni, vous n'appelez jamais /challenge vous-même : le widget s'en charge. Pour votre propre extension, seul /verify est obligatoire.
Authentification
| Point d'accès | Clé | Utilisée où |
|---|---|---|
| GET /api/v2/challenge | cc_pub_… | dans le navigateur — peut être publique |
| POST /api/v2/verify | cc_sec_… | côté serveur uniquement — ne jamais la diffuser |
| GET /api/v2/status | cc_sec_… | côté serveur uniquement |
La clé va toujours dans l'en-tête X-CaptchaCore-Key, jamais dans l'URL.
GET /api/v2/challenge
Demande un calcul accompagné de sa politique. Paramètre de requête facultatif : form_type (voir les politiques de formulaire). Répond avec HTTP 200.
{
"challenge_id": "ch_a45cd15b0d6d2dc6",
"nonce": "a45cd15b…1d50", // einmalig, 5 Minuten gültig
"expires_at": 1788860066,
"policy": {
"mode": "adaptive",
"challenge_type": "sha256_pow", // Zusatzprüfung steht ggf. unter "step_up"
"challenge_types": ["sha256_pow"],
"difficulty": 4, // führende Nullen im Hash
"algorithm": "sha256",
"time_budget_ms": 500,
"requires_interaction": false,
"requires_stepup_on_submit": false,
"memory_hard_enabled": false,
"form_type": "contact",
"site_profile": "balanced",
"uam_level": 0 // 0–3, Under-Attack-Stufe
},
"bindings": { // bindet den Token an Site, Origin und Formular
"site_id": 2,
"origin": "https://example.com",
"form_type": "contact",
"issued_at": 1788859766,
"expires_at": 1788860066,
"token_ttl_sec": 300
},
"bindings_signature": "CBkATjVc…RDg==", // Ed25519, unveränderlich mitschicken
"signing_key_id": "k_397d99d39156c5f5",
"widget": { /* im Admin gepflegtes Erscheinungsbild */ },
"widget_version": "3.0.0"
}
Important pour vos propres clients : bindings et bindings_signature doivent revenir inchangés dans le jeton. S'ils manquent ou sont modifiés, /verify répond block.
POST /api/v2/verify
Vérifie le jeton du formulaire. En règle générale, la réponse est HTTP 200, y compris en cas de refus. Analysez le corps, pas le code de statut.
// Request { "token": "<Wert des Feldes captchacore_token>", "form_type": "contact", // optional, steuert die Policy "page_url": "https://…", // optional, nur für Auswertungen "client_ip": "203.0.113.42" // empfohlen: IP des Besuchers } // Response { "valid": true, // false bei block UND bei step_up "decision": "allow", // allow | challenge | step_up | block "action": "allow", // identisch zu decision (älterer Feldname) "request_id": "…", // für Rückfragen an den Support "risk_score": 8, // 0–100, höher = riskanter "confidence": 0.94, // 0.0–1.0 Signalabdeckung "reasons": ["pow_valid", "behavior_human_like"], "step_up": null // bei decision=step_up: Daten für die Zusatzprüfung }
Comment traiter decision
| decision | valid | Comportement recommandé |
|---|---|---|
| allow | true | Traitez le formulaire normalement. |
| challenge | true | Laissez passer mais journalisez. Ajoutez éventuellement une vérification à vous, par exemple un e-mail de confirmation. |
| step_up | false | Ne refusez PAS d'emblée. Le widget effectue lui-même la vérification supplémentaire ; rendez le formulaire à l'utilisateur avec un message aimable. |
| block | false | Refusez. Affichez une erreur sans détail afin que les attaquants n'apprennent rien. |
GET /api/v2/status
Disponibilité et niveau d'attaque actuel du site. Convient à un contrôle de santé dans votre extension.
{ "status": "ok", "under_attack": false, "version": "2.x" }
Codes de statut HTTP
| Code | Corps | Cause et réaction |
|---|---|---|
| 200 | {"valid": …} | Cas normal, y compris en cas de refus. Analysez le corps. |
| 401 | {"error":"Missing API key"} | L'en-tête X-CaptchaCore-Key est absent. |
| 401 | {"error":"Invalid API key"} | Clé erronée, révoquée ou d'un autre site. C'est aussi le cas lorsque la clé publique est utilisée sur /verify. |
| 403 | {"error": …} | L'origine ne figure pas parmi les domaines autorisés du site. |
| 200 | {"valid": false, "reasons": ["invalid_request"]} | Le champ obligatoire token est absent ou inutilisable. |
| 200 | {"valid": false, "reasons": ["rate_limited"]} | La limite de vérification du site est atteinte. Refusez, ne laissez pas passer. |
| 429 | — | Uniquement sur /challenge (limite par IP du visiteur). Au-delà de la limite, verify répond avec 200 et « refusé ». |
| 401 | {"error":"Invalid API key"} | Également si l’organisation a été supprimée ou désactivée : ses clés ne sont alors plus valides. |
| 503 | {"error":"Account suspended"} | Compte suspendu en raison d’un paiement en attente. Seulement /verify et /status ; les challenges continuent de fonctionner. La protection est suspendue et votre intégration applique sa règle de fail-open afin que vous puissiez continuer à vous connecter. |
| 5xx | — | Un incident de notre côté. Votre règle fail-open ou fail-closed s'applique. |
Limites de débit
| Point d'accès | Limite | Compté par |
|---|---|---|
| GET /api/v2/challenge | 300 / min | Réseau du visiteur et site (IPv6 par /64) ; 1200 / min par réseau sur tous les sites |
| POST /api/v2/verify | 600 / min | clé de site du client |
| POST /api/v2/verify | 30 / min | Clé du site et IP du visiteur (client_ip, IPv6 par /64) |
Verify est compté par site, pas par IP. Votre serveur peut donc vérifier autant de formulaires que votre trafic l'exige, sans se bloquer lui-même.
Seuls les tokens d’un challenge réellement émis comptent dans la limite par site. Les requêtes parasites d’un attaquant se heurtent à la limite par IP de visiteur et n’épuisent pas le contingent de vos vrais visiteurs. Pour cela, transmettez client_ip, comme le font toutes les intégrations officielles.
Webhooks
CaptchaCore prévient vos propres systèmes lorsqu’il se passe quelque chose qui mérite une réaction : quota atteint, mode under-attack déclenché, compte bloqué ou débloqué. Cela se configure dans l’espace client sous Sites → Webhooks (à partir de l’offre Professional).
Événements
| Événement | Quand |
|---|---|
| usage.warning | Quota mensuel utilisé à 80 % ou 90 % |
| usage.limit_reached | Quota mensuel atteint — les vérifications suivantes sont refusées |
| site.under_attack.activated | Mode under-attack d’un site activé (manuellement ou automatiquement) |
| site.under_attack.deactivated | Mode under-attack d’un site terminé |
| organisation.blocked | Compte bloqué (p. ex. facture impayée) — les appels API sont refusés |
| organisation.unblocked | Compte de nouveau débloqué |
| webhook.test | Événement de test depuis l’espace client |
Ce qui arrive
Un POST avec un corps JSON. Trois en-têtes aident à l’identifier et à le vérifier :
POST /ihr-endpunkt HTTP/1.1
Content-Type: application/json
X-CaptchaCore-Event: usage.limit_reached
X-CaptchaCore-Delivery: 5f1c2c1e-… // eindeutig je Zustellung, gleich bei Wiederholungen
X-CaptchaCore-Timestamp: 1758196800
X-CaptchaCore-Signature: sha256=3b2a…
{
"event": "usage.limit_reached",
"occurred_at": "2026-09-18T14:00:00+02:00",
"organisation_id": 42,
"data": { "threshold_percent": 100, "used": 10000, "limit": 10000, "plan": "pro", "period": "2026-09" }
}Vérifier la signature
La signature est un HMAC-SHA256 sur « timestamp.body » avec la clé de l’espace client. Comparez en temps constant et refusez les horodatages de plus de cinq minutes — cela empêche le rejeu de requêtes interceptées.
$secret = getenv('CAPTCHACORE_WEBHOOK_SECRET'); $body = file_get_contents('php://input'); $timestamp = $_SERVER['HTTP_X_CAPTCHACORE_TIMESTAMP'] ?? ''; $expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret); if (abs(time() - (int) $timestamp) > 300 || ! hash_equals($expected, $_SERVER['HTTP_X_CAPTCHACORE_SIGNATURE'] ?? '')) { http_response_code(401); exit; } $event = json_decode($body, true); // … verarbeiten, dann schnell mit 2xx antworten http_response_code(204);
Livraison et nouvelles tentatives
- Répondez avec un statut 2xx en moins de 5 secondes — traitez le reste de façon asynchrone.
- En cas d’erreur ou de délai dépassé, la livraison est retentée jusqu’à trois fois (après 30 secondes puis 5 minutes) avec le même ID de livraison — rendez votre traitement idempotent grâce à lui.
- Après dix échecs consécutifs, le webhook est désactivé ; l’espace client indique la raison et permet de le réactiver.
- Chaque livraison, avec code de réponse, durée et extrait de réponse, figure sous « Livraisons » — utile aussi pour le dépannage de votre côté.
Versionnement et stabilité
Qui maintient une extension doit savoir sur quoi compter. Voici nos engagements.
La version dans le chemin reste stable
Au sein de /api/v2, nous ne supprimons ni ne renommons de champs de réponse. De nouveaux champs peuvent apparaître à tout moment : lisez les réponses avec tolérance et n'échouez pas sur des clés inconnues.
V1 est obsolète
L’ancienne interface de vérification sous /api/v1 et le widget captchacore.min.js ne restent actifs que pour les anciennes intégrations ; le widget affiche aux visiteurs un avis de mise à jour. Passez à V2 — nous annoncerons la date d’arrêt suffisamment tôt.
Le widget se met à jour tout seul
Via le chemin CDN captchacore-v2.min.js, vous obtenez toujours la version maintenue. N'embarquez pas votre propre copie, sinon vous manquerez les améliorations de la détection des robots.
Nous annonçons les changements
Tout ce qui pourrait affecter des intégrations existantes est annoncé à l'avance sur l'état public du système et par e-mail à l'adresse technique enregistrée.