Loading page
Fetch the endpoint with JSON, read the structured error body, and disable the button only while the request is running.
const form = document.querySelector("form");
const status = document.querySelector("[data-status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button[type=submit]");
button.disabled = true;
status.textContent = "Sending…";
try {
const response = await fetch("https://formivo.faizyab.me/api/f/YOUR_FORM_ID", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
// one key per form fill: retries never create a duplicate lead
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify(Object.fromEntries(new FormData(form))),
});
const body = await response.json();
if (!response.ok) throw new Error(body?.error?.message ?? "Submission failed");
form.reset();
status.textContent = "Thanks — your message was sent.";
} catch (error) {
status.textContent = error.message;
} finally {
button.disabled = false;
}
});201 with { success: true, leadId } on create, 200 when an idempotency key replays, 409 for a paused form or exhausted quota, 429 with Retry-After.
| Symptom | Fix |
|---|---|
| CORS error in the console | The form's origin allow-list does not include your site. |
| Duplicate leads | Disable the button during the request and send an Idempotency-Key. |
| response.json() throws | A redirect was followed; do not send `_redirect` with fetch. |