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:
| Status | Meaning |
|---|---|
200 / 302 | Success (message or redirect) |
400 | Validation failed — check error in the JSON body |
403 | Form is disabled or submission limit reached |
413 | Payload too large (body size exceeded) |
429 | Rate limited — too many responses from this IP |
503 | Form 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.