formconfirmed

Dokumentacja dla deweloperów

Dwa kroki: widżet w formularzu, a następnie sprawdzenie tokenu na serwerze, zanim cokolwiek przetworzysz. API odpowiada jak reCAPTCHA i Turnstile, dodatkowo z akcją i powodami.

Szybki start

1. Dodaj widżet do formularza. Zastąp klucz strony własnym kluczem z panelu.

<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. Zanim wyślesz lub zapiszesz zgłoszenie, wyślij token ze swojego serwera do /v1/verify. Klucz tajny pozostaje na serwerze.

<?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

Wysyłaj pola jako dane formularza (application/x-www-form-urlencoded) lub jako JSON. Użyj krótkiego limitu czasu (3 sekundy).

PoleZnaczenie
secretwymaganeTwój klucz tajny (fcp_sec_…). Nigdy nie umieszczaj go na stronie.
responsewymaganeToken z pola formularza fcp-response. Wysyłaj go także wtedy, gdy jest pusty – nie odrzucaj brakującego tokenu samodzielnie.
remoteipopcjonalneAdres IP odwiedzającego. Zaostrza sygnały częstotliwości i sieci.
contentopcjonalneTreść wiadomości. Filtr wstępny spamu w każdym planie, sprawdzenie treści przez AI zależnie od planu i ustawień. Sprawdzana tylko w pamięci, nie jest zapisywana.
emailopcjonalneAdres e-mail z formularza: rozpoznawane są skrzynki jednorazowe i domeny bez poczty.
hpopcjonalneWartość ukrytego pola fcp-website (honeypot).
expected_purposeopcjonalneCel, dla którego podpisano widżet, np. contact, login, register. Token wydany dla innego celu zostanie odrzucony.
operation_idopcjonalneStały identyfikator operacji (16–128 znaków) – powtórzenia nie liczą się podwójnie. Tylko razem z expected_purpose.
recipientopcjonalneOdbiorca wiadomości akcji (np. reset hasła) na potrzeby limitów na odbiorcę.
form_modeopcjonalneinteractive (domyślnie) lub deferred dla formularzy wysyłanych później.

Odpowiedź

{ "success": true, "score": 0.92, "action": "allow", "reasons": [],
  "error-codes": [], "challenge_ts": "2026-11-06T09:41:12Z", "hostname": "example.com" }
successfalse, gdy akcja to block lub żądanie jest nieprawidłowe.
score0,0 (bot) do 1,0 (człowiek).
actionallow, flag lub block – zalecane postępowanie.
reasonsSygnały, które doprowadziły do wyniku, np. too_fast, honeypot_filled.
error-codesBłędy techniczne, patrz niżej.
challenge_tsCzas rozwiązania zadania (UTC).
hostnameHost, na którym działał widżet.
contentTylko przy sprawdzaniu treści: kategoria i pewność.

Postępowanie z akcją

Gdy usługa jest nieosiągalna

Limit czasu, błąd sieci, 5xx lub nieprawidłowa odpowiedź nigdy nie są zgodą. Zatrzymaj wiadomość z oznaczeniem do moderacji albo pokaż błąd z prośbą o ponowienie. Przyjmij ją normalnie tylko po własnym, niezależnym sprawdzeniu, np. istniejącej weryfikacji konta. W panelu można ustawić zachowanie przy awarii dla każdej witryny.

Kody błędów

missing-input-secretNie wysłano klucza tajnego.
invalid-input-secretKlucz tajny nieznany lub wycofany.
missing-input-responseNie wysłano tokenu.
invalid-input-responseToken nieprawidłowy, wygasły lub już użyty.
purpose-mismatchToken wydano dla innego celu.
purpose-not-allowedTen cel nie jest dozwolony dla witryny (ustawienie w panelu).
site-pausedWitryna jest wstrzymana w panelu.
service-disabledUsługa jest tymczasowo wyłączona.
bad-requestBrakujące pola, za długie lub w złym formacie.
service-unavailableWidżet nie dotarł do usługi – traktuj to jak awarię.

Formularze wysyłane przez JavaScript

W formularzach wysyłanych przez fetch lub XMLHttpRequest najpierw pobierz token i wyślij go w polu fcp-response:

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

Wtyczka formexposed (od wersji 1.8) automatycznie dodaje widżet i sprawdzenie na serwerze do Contact Form 7, WPForms i komentarzy. Wpisz klucz strony i klucz tajny w Wtyczki → formexposed → Ochrona formularzy.

Ochrona danych

Bez plików cookie, nic nie jest zapisywane na urządzeniu, bez fingerprintu. Przetwarzane są: rozwiązane zadanie, czas wypełniania, czy ukryte pole zostało wypełnione oraz – jeśli ją wyślesz – treść wiadomości, sprawdzana tylko w pamięci. Adresy IP tylko skrócone i jako codziennie zmieniany hash. Tekst do polityki prywatności znajdziesz w panelu.