AJAX & fetch()

If your site is a single-page app (React, Vue, Svelte, etc.) or you want to submit without a full page reload, use JavaScript to POST to your formbuild.io endpoint.

JSON submission

Send a JSON body with Content-Type: application/json. Each key becomes a field name in your Inbox.

const response = await fetch(
  "https://formbuild.io/in/YOUR_FORM_ID",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      name: "Jane Doe",
      email: "jane@example.com",
      message: "Hello from my app!",
    }),
  }
);

if (response.ok) {
  // Success — show a thank-you message
} else {
  const err = await response.json();
  // err.error describes what went wrong
}

Form data submission

You can also send FormData — useful when your JavaScript collects values from an existing form element.

const form = document.getElementById("my-form");
const formData = new FormData(form);

const response = await fetch(
  "https://formbuild.io/in/YOUR_FORM_ID",
  {
    method: "POST",
    body: formData,
    // Do NOT set Content-Type — the browser sets it
    // automatically with the correct boundary.
  }
);

Preventing duplicate responses

If a user double-clicks submit or the network retries, you can prevent duplicate responses by sending an Idempotency-Key header. Use a unique value per submission attempt (e.g. a UUID generated on the client).

const response = await fetch(
  "https://formbuild.io/in/YOUR_FORM_ID",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({ email: "jane@example.com" }),
  }
);

If the same key is sent again within 24 hours, we return the original success response without creating a second entry.

Handling errors

The endpoint returns standard HTTP status codes:

StatusMeaning
200 / 302Success (message or redirect)
400Validation failed — check error in the JSON body
403Form is disabled or submission limit reached
413Payload too large (body size exceeded)
429Rate limited — too many responses from this IP
503Form is paused by the owner

CORS

The submission endpoint allows requests from any origin ( Access-Control-Allow-Origin: *), so fetch() from any domain will work without proxy workarounds.

← HTML form · Next: Validations →