Why direct-to-API spam happens
Browser-side protection only works if the attacker loads the browser. Many form bots do not. They scrape your HTML once, extract the endpoint and access key, then send raw POST requests from scripts. That bypasses frontend reCAPTCHA widgets, JavaScript timers, and any hidden fields that are only checked in client code.
For a form backend, the submission endpoint is the security boundary. The endpoint must read the current form settings and decide whether the submission deserves delivery.
The server-side gate order
- Method and content type. Accept POST with JSON, urlencoded, or multipart only.
- IP rate limit. Start with 5 submissions per 60 seconds per IP.
- Origin allow-list. If domains are configured, require Origin or Referer to match the root domain or subdomain.
- Honeypot validation. Check fields like
botcheck,website, andconfirm_emailon the server. - Time trap. Reject submissions sent too quickly after page load or absurdly late.
- Optional CAPTCHA verification. If a secret key exists, verify the token server-side with a timeout.
That is the exact shape we use in splitforms spam protection. Cheap checks run first, expensive network calls run last, and the delivery system only receives submissions that pass every enabled gate.
Origin checks are opt-in for a reason
An origin allow-list is powerful, but it needs to be settings-driven. If a user has not configured allowed domains, do not block the form. Once they add example.com, enforcement should begin on the very next request.
The matching rule should be exact host or subdomain only. www.example.com should match example.com, but example.com.evil.test must not.
Why silent drops beat error messages
Returning 403, 429, or “honeypot failed” teaches the attacker which part to change. For spam gates, a benign200 { success: true } response is safer. The bot thinks the payload worked and keeps sending the same junk, while the backend simply does not deliver it.
What this means for WordPress forms
WordPress sites are frequent targets because bots know the common plugin endpoints. If you use a hosted form backend, lock the form to your domain, keep the honeypot enabled, and verify the direct download plugin or shortcode still includes a form_loaded_at field. See the WordPress setup page.
FAQ
Why do bots POST directly to form APIs?
Because it is cheaper than loading a browser. Once a bot sees an endpoint and access key, it can replay POST requests without loading your page, JavaScript, honeypot script, or CAPTCHA widget.
Does a frontend honeypot stop direct-to-API spam?
Not by itself. The server must validate the honeypot field and drop submissions where it is filled. Anything that only runs in the browser can be bypassed by scripted POST requests.
Should failed spam checks return an error?
Usually no. For spam gates, a silent HTTP 200 response with a fake success body is better because it does not teach bots which check failed.
What is the strongest direct-to-API protection?
Use layered server-side checks: content type, IP rate limit, origin allow-list, honeypot validation, time trap, and optional server-verified CAPTCHA. No single gate is enough.