Referencia de la API
Endpoints, campos de respuesta, códigos de estado, límites y nuestros compromisos de estabilidad.
En esta página
Referencia de la API (V2)
URL base: https://api.captchacore.eu: todos los endpoints responden con JSON. Si usa el widget suministrado, nunca llamará usted a /challenge; de eso se encarga el widget. Para un complemento propio solo /verify es obligatorio.
Autenticación
| Endpoint | Clave | Dónde se usa |
|---|---|---|
| GET /api/v2/challenge | cc_pub_… | en el navegador: puede ser pública |
| POST /api/v2/verify | cc_sec_… | solo en el servidor: nunca la entregue |
| GET /api/v2/status | cc_sec_… | solo en el servidor |
La clave va siempre en la cabecera X-CaptchaCore-Key, nunca en la URL.
GET /api/v2/challenge
Solicita un cálculo junto con su política. Parámetro de consulta opcional: form_type (véanse las políticas de formulario). Responde con HTTP 200.
{
"challenge_id": "ch_a45cd15b0d6d2dc6",
"nonce": "a45cd15b…1d50", // einmalig, 5 Minuten gültig
"expires_at": 1788860066,
"policy": {
"mode": "adaptive",
"challenge_type": "sha256_pow", // oder argon2id_pow, interaction_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"
}
Importante para clientes propios: bindings y bindings_signature deben volver al token sin modificar. Si faltan o se alteran, /verify responde con block.
POST /api/v2/verify
Comprueba el token del formulario. Por regla general responde con HTTP 200, también en caso de rechazo. Evalúe el cuerpo, no el código de estado.
// Request { "token": "<Wert des Feldes captchacore_token>", "form_type": "contact", // optional, steuert die Policy "page_url": "https://…" // optional, nur für Auswertungen } // Response { "valid": true, // false bei block UND bei step_up "decision": "allow", // allow | challenge | step_up | block "action": "allow", // identisch zu decision, für V1-Kompatibilität "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 }
Cómo tratar decision
| decision | valid | Comportamiento recomendado |
|---|---|---|
| allow | true | Procese el formulario con normalidad. |
| challenge | true | Déjelo pasar pero regístrelo. Opcionalmente añada una comprobación propia, como un correo de confirmación. |
| step_up | false | NO rechace de plano. El widget realiza la comprobación adicional por sí mismo; devuelva el formulario al usuario con un mensaje amable. |
| block | false | Rechace. Muestre un error sin detalles para que los atacantes no aprendan nada. |
GET /api/v2/status
Disponibilidad y nivel actual de ataque del sitio. Adecuado para una comprobación de estado en su complemento.
{ "status": "ok", "under_attack": false, "version": "2.x" }
Códigos de estado HTTP
| Código | Cuerpo | Causa y reacción |
|---|---|---|
| 200 | {"valid": …} | Caso normal, también en caso de rechazo. Evalúe el cuerpo. |
| 401 | {"error":"Missing API key"} | Falta la cabecera X-CaptchaCore-Key. |
| 401 | {"error":"Invalid API key"} | Clave incorrecta, revocada o de otro sitio. También ocurre si se usa la clave pública en /verify. |
| 403 | {"error": …} | El origen no está entre los dominios permitidos del sitio. |
| 422 | {"message": …} | Falta un campo obligatorio, normalmente token. |
| 429 | — | Se alcanzó el límite de peticiones. Trátelo como una caída, véase el manejo de errores. |
| 5xx | — | Una avería por nuestra parte. Se aplica su regla fail-open o fail-closed. |
Límites de peticiones
| Endpoint | Límite | Contado por |
|---|---|---|
| GET /api/v2/challenge | 60 / min | IP del visitante |
| POST /api/v2/verify | 600 / min | clave de sitio del cliente |
Verify se cuenta por sitio, no por IP. Su servidor puede así comprobar tantos formularios como tráfico tenga su sitio, sin bloquearse a sí mismo.
Webhooks
CaptchaCore avisa a sus propios sistemas cuando ocurre algo a lo que quiera reaccionar: cuota alcanzada, modo under-attack activado, cuenta bloqueada o desbloqueada. Se configura en el área de cliente en Sitios → Webhooks (a partir del plan Professional).
Eventos
| Evento | Cuándo |
|---|---|
| usage.warning | Cuota mensual al 80 % o 90 % |
| usage.limit_reached | Cuota mensual alcanzada: se rechazan más verificaciones |
| site.under_attack.activated | Modo under-attack de un sitio activado (manual o automáticamente) |
| site.under_attack.deactivated | Modo under-attack de un sitio finalizado |
| organisation.blocked | Cuenta bloqueada (p. ej. factura pendiente): se rechazan las llamadas a la API |
| organisation.unblocked | Cuenta desbloqueada de nuevo |
| webhook.test | Evento de prueba desde el área de cliente |
Qué llega
Un POST con cuerpo JSON. Tres cabeceras ayudan a identificarlo y verificarlo:
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" }
}Verificar la firma
La firma es un HMAC-SHA256 sobre «timestamp.body» con la clave del área de cliente. Compare en tiempo constante y rechace marcas de tiempo de más de cinco minutos: así evita repeticiones de solicitudes interceptadas.
$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);
Entrega y reintentos
- Responda con un estado 2xx en menos de 5 segundos; procese lo costoso de forma asíncrona.
- Ante errores o tiempo de espera se reintenta hasta tres veces (a los 30 segundos y a los 5 minutos) con el mismo ID de entrega; haga su procesamiento idempotente con él.
- Tras diez fallos consecutivos el webhook se desactiva; en el área de cliente verá el motivo y podrá reactivarlo.
- Cada entrega, con código de respuesta, duración y extracto de la respuesta, figura en «Entregas», también para depurar en su lado.
Versionado y estabilidad
Quien mantiene un complemento necesita saber con qué puede contar. Estos son nuestros compromisos.
La versión de la ruta se mantiene estable
Dentro de /api/v2 no eliminamos ni renombramos campos de respuesta. Pueden aparecer campos nuevos en cualquier momento: lea las respuestas con tolerancia y no falle ante claves desconocidas.
V1 sigue disponible por ahora
La interfaz antigua en /api/v1 se sigue atendiendo, pero ya no recibe señales nuevas. Las integraciones nuevas deberían usar exclusivamente V2.
El widget se actualiza solo
A través de la ruta del CDN captchacore-v2.min.js siempre obtiene la versión mantenida. No incluya una copia propia o se perderá las mejoras en la detección de bots.
Anunciamos los cambios
Todo lo que pueda afectar a integraciones existentes se anuncia con antelación en el estado público del sistema y por correo a la dirección técnica registrada.