AJAX submissions
By default, Formward responds to a form POST with a 302 redirect (the standard browser behaviour). For single-page apps or custom UIs where you want to stay on the page and handle the response yourself, send the request with an Accept: application/json header and Formward returns 200 { ok: true, id } instead. An X-Requested-With header works too, but Accept is the one to use.
Detection
Formward detects an AJAX request by inspecting the incoming headers. Either of these triggers JSON mode, and Accept is the recommended one:
Acceptheader containsapplication/jsonX-Requested-Withheader is present (any value). It is allowed in the cross-origin preflight, so it works from the browser, butAcceptis a CORS-safelisted header and never needs a preflight entry.
fetch() example
async function submitForm(form) {
const data = new FormData(form);
const res = await fetch("https://forms.formward.eu/f/<formId>", {
method: "POST",
headers: {
Accept: "application/json",
},
body: new URLSearchParams(data),
});
if (!res.ok) {
const body = await res.json().catch(() => ({}));
// See status codes in Responses & redirects
throw new Error(body.error ?? `HTTP ${res.status}`);
}
const { ok, id } = await res.json();
// ok: true, id: "<submissionId>"
console.log("Submission recorded:", id);
}Successful response
HTTP/1.1 200 OK
Content-Type: application/json
{ "ok": true, "id": "clxyz123..." }The id is the submission ID assigned by Formward. You can use it to cross-reference entries in the dashboard.
Error responses
Error responses are also JSON when the request was sent in AJAX mode. The body shape is { ok: false, error: string }, with an additional upgrade: true field on plan-limit errors. See Responses & redirects for the full status code table.
Sending JSON vs form-encoded
The ingestion server accepts application/x-www-form-urlencoded bodies (standard form POST), application/json bodies and multipart/form-data (for file uploads). When submitting via fetch the simplest option is new URLSearchParams(data) as the body: it produces a form-encoded body without needing to set a Content-Type header manually. To send JSON, set Content-Type: application/json and pass JSON.stringify(data); the body must be a JSON object.
CORS
Cross-origin requests are gated by the allowed origins list on your form. If the Origin header of the request is not on that list (and the list is non-empty), the server returns 403. Add your site's origin in the form settings before going live.