/v1/forms
Screen a contact, feedback, lead or quote-request form submission in one call.
- METHOD
- POST
- BODY CAP
- 24 KiB
- CHECKS
- 42
- FINDING CODES
- 2
POST /v1/forms screens a form submission: the message, and whatever you know about who sent
it. It is the layer after a CAPTCHA, which stops scripts that cannot solve one; this catches the
pitches, link drops and humans-for-hire that can.
Request#
{
"message": "Hi, I noticed your website is not on the first page of Google. We offer SEO services.",
"email": "hello@example-agency.com",
"name": "Jim from example-agency.com",
"subject": "Quick question",
"ip": "203.0.113.7",
"honeypot": "",
"fill_time_ms": 1800,
"user_agent": "Mozilla/5.0 ..."
}
| Field | Type | Required | Notes |
|---|---|---|---|
message |
string | yes | Up to 16 KiB. |
email |
string | no | Unlocks the email and domain checks. |
name |
string | no | Unlocks signup.suspicious_name and form.link_in_name. |
subject |
string | no | Unlocks form.link_in_subject. |
ip |
string | no | The submitter’s address, forwarded by your backend. Unlocks the ip.* checks. |
honeypot |
string | no | A hidden field’s value. Send "" when it stayed empty. |
fill_time_ms |
integer | no | Milliseconds from render to submit. Omit when unknown; 0 means instant. |
user_agent |
string | no | The submitter’s User-Agent header, not your server’s. |
Every optional field unlocks checks. A check whose field is missing appears in checks_skipped
with reason input and the field under requires.
Checks this gate runs#
All run concurrently, in one pass.
| Runs on | Checks |
|---|---|
message |
Every /v1/spam check, including spam.sales_pitch, spam.off_platform_contact and the model-backed spam.likely_spam; the /v1/prompts rule checks, for messages that reach an AI triage step (the prompts model check is not run). |
email |
The /v1/emails checks and the /v1/domains checks, on the address and its domain. |
ip |
The /v1/ip checks. |
name, subject |
form.link_in_name and signup.suspicious_name on the name; form.link_in_subject on the subject. |
honeypot, fill_time_ms, user_agent |
The signup.* behaviour checks, which keep their codes. |
data.matches lists the text matches from the message checks, with offsets into message and
never the matched text.
Credits are the sum of the components, as for /v1/signups.
Example#
curl -s -X POST https://api.stormdoor.dev/v1/forms \
-H "Authorization: Bearer sk_live_..." \
-H "content-type: application/json" \
-d '{"message":"I noticed your website is not on the first page of Google. We offer SEO services.","name":"Jim from acme.com"}'
Do not proxy the raw checks_skipped array to your end users; it is a map of what this API does
not look at.
Finding codes#
Each code links to its own page with what it looks at, why it matters and what to do.