formconfirmed

Entwickler-Dokumentation

Zwei Schritte: das Widget in Ihr Formular, dann eine serverseitige Prüfung des Tokens, bevor Sie etwas verarbeiten. Die API antwortet wie reCAPTCHA und Turnstile, dazu mit einer Aktion und Gründen.

Schnellstart

1. Das Widget in Ihr Formular setzen. Den Site-Key durch Ihren eigenen aus dem Dashboard ersetzen.

<script src="https://formconfirmed.com/v1/widget.js" async defer></script>

<form method="post" action="/contact">
  ...
  <div class="fcp-widget" data-sitekey="fcp_pub_..." data-purpose="contact"></div>
  <button type="submit">Send</button>
</form>

2. Bevor Sie die Absendung verschicken oder speichern, das Token von Ihrem Server an /v1/verify senden. Der Secret-Key bleibt auf dem Server.

<?php
$ch = curl_init('https://formconfirmed.com/v1/verify');
curl_setopt_array($ch, [
    CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 3,
    CURLOPT_POSTFIELDS => http_build_query([
        'secret'           => getenv('FCP_SECRET'),
        'response'         => $_POST['fcp-response'] ?? '',
        'remoteip'         => $_SERVER['REMOTE_ADDR'] ?? '',
        'content'          => $_POST['message'] ?? '',
        'expected_purpose' => 'contact',
    ]),
]);
$res = json_decode((string)curl_exec($ch), true);

if (!is_array($res) || !isset($res['success'], $res['action'])) {
    $decision = 'hold';     // outage: never a pass
} elseif (!$res['success']) {
    $decision = 'reject';
} else {
    $decision = $res['action'] === 'flag' ? 'hold' : 'accept';
}

POST /v1/verify

https://formconfirmed.com/v1/verify

Die Felder als Formulardaten (application/x-www-form-urlencoded) oder als JSON senden. Ein kurzes Zeitlimit verwenden (3 Sekunden).

FeldBedeutung
secretPflichtIhr Secret-Key (fcp_sec_…). Nie in die Seite schreiben.
responsePflichtDas Token aus dem Formularfeld fcp-response. Auch leer mitschicken – ein fehlendes Token nicht selbst ablehnen.
remoteipoptionalIP-Adresse des Besuchers. Schärft Raten- und Netzsignale.
contentoptionalNachrichtentext. Spam-Vorfilter in jedem Tarif, KI-Inhaltsprüfung je nach Tarif und Einstellung. Wird nur im Arbeitsspeicher geprüft, nicht gespeichert.
emailoptionalE-Mail-Adresse aus dem Formular: Wegwerf-Anbieter und Domains ohne Mail werden erkannt.
hpoptionalWert des versteckten Feldes fcp-website (Honeypot).
expected_purposeoptionalDer Zweck, für den das Widget signiert wurde, z. B. contact, login, register. Ein Token für einen anderen Zweck wird abgelehnt.
operation_idoptionalFeste Kennung der Geschäftsaktion (16–128 Zeichen) – Wiederholungen zählen nicht doppelt. Nur zusammen mit expected_purpose.
recipientoptionalEmpfänger einer Aktionsmail (z. B. Passwort zurücksetzen) für die Grenzen je Empfänger.
form_modeoptionalinteractive (Standard) oder deferred für Formulare, die später abgeschickt werden.

Antwort

{ "success": true, "score": 0.92, "action": "allow", "reasons": [],
  "error-codes": [], "challenge_ts": "2026-11-06T09:41:12Z", "hostname": "example.com" }
successfalse, wenn die Aktion block lautet oder die Anfrage ungültig ist.
score0,0 (Bot) bis 1,0 (Mensch).
actionallow, flag oder block – die empfohlene Behandlung.
reasonsSignale, die zum Ergebnis geführt haben, z. B. too_fast, honeypot_filled.
error-codesTechnische Fehler, siehe unten.
challenge_tsZeitpunkt, zu dem die Aufgabe gelöst wurde (UTC).
hostnameHost, auf dem das Widget lief.
contentNur mit Inhaltsprüfung: Kategorie und Sicherheit.

Umgang mit der Aktion

Wenn der Dienst nicht erreichbar ist

Zeitlimit, Netzfehler, 5xx oder eine ungültige Antwort sind nie eine Freigabe. Die Nachricht markiert in die Moderation legen oder einen Fehler mit der Bitte um einen neuen Versuch zeigen. Normal annehmen nur nach einer eigenen, unabhängigen Prüfung, etwa einer bestehenden Kontoprüfung. Im Dashboard lässt sich das Ausfallverhalten je Site einstellen.

Fehlercodes

missing-input-secretKein Secret-Key gesendet.
invalid-input-secretSecret-Key unbekannt oder zurückgezogen.
missing-input-responseKein Token gesendet.
invalid-input-responseToken ungültig, abgelaufen oder schon verwendet.
purpose-mismatchDas Token wurde für einen anderen Zweck ausgestellt.
purpose-not-allowedDieser Zweck ist für die Site nicht erlaubt (Einstellung im Dashboard).
site-pausedDie Site ist im Dashboard pausiert.
service-disabledDer Dienst ist vorübergehend abgeschaltet.
bad-requestFelder fehlen, sind zu lang oder haben das falsche Format.
service-unavailableDas Widget hat den Dienst nicht erreicht – wie einen Ausfall behandeln.

Formulare, die per JavaScript abgeschickt werden

Bei Formularen, die per fetch oder XMLHttpRequest abgeschickt werden, zuerst das Token holen und im Feld fcp-response mitsenden:

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const data = new FormData(form);
  data.set('fcp-response', await window.__fcpWidget.token(form));
  await fetch(form.action, { method: 'POST', body: data });
});

WordPress

Das formexposed-Plugin (ab Version 1.8) setzt Widget und Serverprüfung in Contact Form 7, WPForms und die Kommentare automatisch ein. Site-Key und Secret-Key unter Plugins → formexposed → Formularschutz eintragen.

Datenschutz

Keine Cookies, nichts auf dem Gerät gespeichert, kein Fingerprint. Verarbeitet werden: die gelöste Aufgabe, die Ausfüllzeit, ob das versteckte Feld ausgefüllt wurde und – wenn Sie ihn mitschicken – der Nachrichtentext, der nur im Arbeitsspeicher geprüft wird. IP-Adressen nur gekürzt und als täglich wechselnder Hash. Einen Text für Ihre Datenschutzerklärung finden Sie im Dashboard.