Integration guide
Send JSON or FormData with fetch, preserve accessible UI states, and handle FormDex failures without losing the visitor’s input.
Step by step
Use JSON for text-only payloads. Use FormData for native forms, honeypot fields, captcha widgets, or file attachments.
Set X-API-Key for JSON requests. A native FormData request may include _api_key instead; do not set Content-Type manually for FormData because the browser must add its boundary.
Check response.ok, parse the JSON body, show a useful inline error, and preserve the entered values when the request fails.
Disable the submit button while pending and restore it in finally. Only clear the form after a successful response.
Keep allowed origins strict, use the honeypot in the actual form, and enable captcha for higher-risk public endpoints.
Honeypot in this integration
Required when JavaScript submits a public browser form. Put the visually hidden text input inside the same form before creating FormData. FormData will include the empty field automatically; never set or remove it in legitimate client code.
Read the honeypot fundamentals →Working example
<form id="contact-form">
<!-- HONEYPOT: exact FormDex field name; real visitors never fill it. -->
<div aria-hidden="true" style="position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden;">
<label>Leave this field empty
<input type="text" name="company" tabindex="-1" autocomplete="off" />
</label>
</div>
<label>Email <input type="email" name="email" required /></label>
<label>Message <textarea name="message" required></textarea></label>
<label>Attachments <input type="file" name="attachments" accept=".pdf,.jpg,.jpeg,.png" multiple /></label>
<p id="form-error" role="alert"></p>
<button type="submit">Send enquiry</button>
</form>
<script>
const form = document.querySelector("#contact-form");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button[type=submit]");
button.disabled = true;
try {
const response = await fetch("https://YOUR_FORMDEX_DOMAIN/api/forms/FORM_ID", {
method: "POST",
headers: { "X-API-Key": "YOUR_API_KEY" },
body: new FormData(form)
});
const result = await response.json();
if (!response.ok) throw new Error(result.message || result.error || "Submission failed");
form.reset();
} catch (error) {
document.querySelector("#form-error").textContent = error.message;
} finally {
button.disabled = false;
}
});
</script>Troubleshooting
CORS error
Add the exact frontend origin and verify Test mode is not masking a production configuration problem.
415 Unsupported content type
Use JSON, URL-encoded data, or FormData.
Captcha verification failed
Obtain a fresh token for each attempt and use keys registered for the current hostname.
Repeated submissions
Disable the submit control while the request is pending.