Sending with JavaScript

By default, your visitors leave your page when they send the form, and land on your redirect URL. If you'd rather keep them on the page, send the form with fetch:

<form id="contact" action="https://fwdr.io/f/YOUR_TOKEN" method="POST">
  <input type="email" name="email" required />
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>
<p id="contact-status" hidden></p>

<script>
  const form = document.getElementById("contact");
  const status = document.getElementById("contact-status");

  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    try {
      const response = await fetch(form.action, {
        method: "POST",
        body: new FormData(form),
      });
      const { error } = await response.json();
      status.textContent = error ?? "Thanks! Your message is on its way.";
      if (!error) form.reset();
    } catch {
      status.textContent = "Something went wrong, please try again.";
    }
    status.hidden = false;
  });
</script>

FormData takes care of files and captchas for you. If you prefer, you can also send JSON, with a Content-Type: application/json header.

What we answer

When the form is sent from a script, we don't redirect: we answer in JSON instead.

StatusAnswer
200{"ok": true}: got it. Messages caught by the captcha get the same answer, so bots don't learn anything.
400{"error": "Your message is empty."}
404{"error": "This form does not exist, or it was deleted."}
422{"error": "You can attach up to 10 files, adding up to less than 25 MB."}

Error messages are written for your visitors, so you can show them as is.

From a server

Browsers tell us when a request comes from a script. Other tools don't, so add an Accept: application/json header to get the answers above:

curl -X POST https://fwdr.io/f/YOUR_TOKEN \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"email": "[email protected]", "message": "Hello!"}'

Without it, we answer like we do to a regular form: a 302 redirect to your redirect URL. Nested objects and arrays are handled like grouped fields.

Next: Managing submissions