The form backend job, and what is actually in it

A form backend is the part nobody wants to write twice: accept a POST from a page you do not control, decide whether the body is usable, throw away the bot traffic, keep what is left, and tell someone it arrived. SubmitHarbor does those five things behind one URL.

Five jobs behind one URL

Accept
One POST endpoint per project that answers both JSON and ordinary form bodies, with CORS preflight handled so a browser on your own domain is not blocked.
Validate
Required email and message, 20 fields maximum, 5,000 characters per field, and a 64 KB body ceiling — enforced server-side, not in the page.
Filter
Honeypot fields, an optional origin allow-list, and a fixed-window rate limit, each answering in a way that does not teach a bot what tripped.
Store
A structured document per submission with the fields, the sending origin, a shortened user agent, and the time received.
Notify
An optional email to the project's notification address for each stored submission, sent only from a sender the product owns.

A JSON request

Send a flat object. String and number values are read and trimmed; anything else in the body is ignored rather than stored.

Submitting JSON from the browser
const response = await fetch("https://www.submitharbor.com/api/submit/sh_your_project_key", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name, email, message }),
});

const result = await response.json();

if (!response.ok) {
  // result.error is a plain sentence, safe to show the visitor.
  showError(result.error);
} else if (result.filtered) {
  // A honeypot was populated. Say thank you anyway.
  showThanks();
} else {
  showThanks();
}
A successful response
{
  "ok": true,
  "stored": true,
  "mode": "firebase",
  "id": "9f2c0f1e4b7a48d2",
  "notificationSent": true
}

stored tells you whether the submission was written down, and mode tells you why. A configured project returns firebase; the shared demo returns preview and echoes the validated submission back instead of keeping it.

An ordinary form body

The same endpoint reads application/x-www-form-urlencoded and multipart form data, so a native HTML form and a server-side script both work without a JSON wrapper.

The same submission as a form body
curl -X POST https://www.submitharbor.com/api/submit/sh_your_project_key \
  -d "email=ada@example.com" \
  -d "message=Please send the pricing sheet." \
  -d "name=Ada"

Field names may contain letters, numbers, underscores, and hyphens. Names outside that set are refused rather than silently renamed, so what you send is what you later read in the inbox and in a CSV export.

What comes back when it does not work

Every failure is a status code plus a single sentence. Nothing is swallowed and turned into a false success.

A validation failure
HTTP/1.1 422 Unprocessable Content

{ "ok": false, "error": "Enter a valid email address." }

Four outcomes are worth branching on in an integration. The rest are configuration problems you fix once rather than handle in code.

ResponseMeaningWhen you get it
201 CreatedAcceptedThe submission passed validation. The JSON body reports whether it was stored and includes an X-RateLimit-Remaining header.
200 OKFilteredA honeypot field was populated. The response reports filtered: true and stored: false so a bot cannot tell it was caught.
422 Unprocessable ContentValidation failedA field limit was exceeded, a field name was unusable, or email and message did not pass their checks. The error string is safe to show a visitor.
429 Too Many RequestsRate limitedMore than 20 submissions per minute from one address to one endpoint. A Retry-After header is included.

Treat a filtered response the same as a success in your interface. Telling a bot it was caught only teaches whoever wrote it what to change.

What SubmitHarbor does not do

Worth reading before you build on it. These limits apply today.

  • The shared signed-out demo validates and echoes a preview; durable endpoints, storage, and notifications require a configured signed-in project.
  • SubmitHarbor does not promise an uptime SLA, attachments, CAPTCHA providers, webhooks, CRM integrations, or unlimited submissions.
  • Origin checks and honeypots reduce common abuse but do not replace a complete security and privacy review for sensitive forms.

Questions about form backend

What does a form backend do that my host does not?

A static host serves files; it has nowhere to put a POST. A form backend accepts the request, validates it server-side, filters bot traffic, stores the result, and notifies you.

Does it take JSON or form bodies?

Both, on the same endpoint. It reads the Content-Type and parses JSON objects, URL-encoded bodies, and multipart form data.

What is stored for each submission?

The submitted fields, the sending origin, a shortened user-agent string, the time received, and a read or unread state. Honeypot and redirect fields are consumed rather than stored.