Submit endpoint

Every form has one public endpoint. It is the only URL your site needs, and it answers CORS preflights and stamps CORS headers on every response, so it can be called from any origin.

https://sendform.net/!<form_id>

A language prefix is accepted but never required: https://sendform.net/en/!<form_id> behaves identically.

Failures are returned with HTTP 200 and an error key rather than a 4xx status, so that a plain HTML form still renders a usable page. Always branch on the payload.

POST /!{form_id}

Submits the form. The body may be application/x-www-form-urlencoded, multipart/form-data (required for uploads) or JSON. Send Accept: application/json to get a JSON response; otherwise the endpoint renders a confirmation page, or redirects to the form's configured redirect URL on success.

Contact form fields:

Field Type Required Description
email string yes The submitter's address. Validated and normalized.
message string yes Message body. Truncated at 3000 characters.
_hp string no Honeypot. A non-empty value marks the submission as spam.
_ts string no Page render time in epoch seconds. Under 2 seconds old means spam.
antibot string no Proof-of-JS token. Mandatory when the form has "require JS" enabled.
anything else string no Stored as extra fields: max 25 keys, keys 64 chars, values 3000 chars.
file parts file no Attachments, when the form has uploads enabled. See File uploads.

Feedback forms take rating, and optionally comment and page, instead - see Feedback widget.

Request:

curl -H "Accept: application/json" \
     -d "email=you@example.com" \
     -d "message=Hello" \
     -d "company=Example Ltd" \
     https://sendform.net/!a8Kz3mXq12

Response:

{
  "success": true,
  "form_id": "a8Kz3mXq12",
  "received": {
    "email": "you@example.com",
    "message": "Hello",
    "fields": { "company": "Example Ltd" }
  }
}

received.fields is present only when the submission carried extra fields. Every failure mode is listed in Errors.

Delivery - the notification email, extra recipients, webhooks and the autoresponder - happens after the response is sent, so a slow inbox or a failing webhook never delays the submitter.

GET /!{form_id}

Renders a small test console for the form: a submit form for contact forms, or a live widget preview plus the embed snippet for feedback forms. Useful for checking an endpoint before wiring it into your site.

GET /!{form_id}/token

Issues a proof-of-JS antibot token. CORS-enabled and stateless - the token is HMAC-signed, so no session or cookie is involved.

curl -H "Accept: application/json" https://sendform.net/!a8Kz3mXq12/token
{ "token": "1754812800.Kx8fQ2mA.9f2cV1r..." }

Send the value back as the antibot field on the submit. A token is bound to its form, valid for 30 minutes, and rejected if it is submitted within 2 seconds of being issued. See Spam protection for when it is required.

GET /widget.js

The hosted feedback widget loader, served with permissive CORS and a one-hour cache header so it can be embedded from any site:

<script src="https://sendform.net/widget.js" async></script>

GET /forms/verify

The landing page for the verification link emailed to a form's notification address. It takes a single-use token query parameter and, on success, marks the address verified and enables the form. You never link to it yourself - SendForm sends it.

Pages that are not endpoints

/ and /contact-form are the marketing pages for the product, not part of the integration surface; they are deliberately not documented here. Everything under the dashboard requires a signed-in session and is likewise out of scope for these docs.