Chapter 01Getting Started & Ingestion
4 min read

HTML, React & Next.js Form Ingestion Guide

Every FormFork endpoint (POST /f/{formId}) accepts standard application/x-www-form-urlencoded, multipart/form-data, and application/json requests without server boilerplate.

Key Technical Takeaways (TL;DR)
  • Send POST requests to https://formfork.io/f/{formId} using standard HTML <form>, fetch(), Axios, or cURL.
  • Include the header Accept: application/json for headless JSON responses, or omit it to trigger automatic browser thank-you/redirect flows.
  • Include a hidden _gotcha field in every form to enable zero-friction honeypot bot quarantine.
  • Auto-provision endpoints from static sites or AI-generated apps via POST /api/v1/submit with an ff_pub_ token.

1. Standard HTML Form POST (Browser Redirect Flow)

Point any native HTML <form> element to your FormFork endpoint URL using method="POST". When submitted without an Accept: application/json header, FormFork validates the payload, stores the submission, and redirects the user to your configured Thank-You URL or hosted confirmation screen.

htmlNative HTML5 Form with Honeypot Protection
<form action="https://formfork.io/f/{form_id}" method="POST">
  <label for="name">Full Name</label>
  <input id="name" type="text" name="name" placeholder="Jane Doe" required />

  <label for="email">Work Email</label>
  <input id="email" type="email" name="email" placeholder="jane@acmecorp.io" required />

  <label for="message">Project Scope</label>
  <textarea id="message" name="message" placeholder="Tell us about your timeline..." required></textarea>

  <!-- Honeypot Bot Protection (Keep hidden and empty) -->
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />

  <button type="submit">Submit Inquiry</button>
</form>

2. React & Next.js Async JSON Fetch (Headless Mode)

For single-page applications (React, Next.js App Router, Vue, Svelte, Astro), send a POST request with Content-Type: application/json and Accept: application/json. FormFork responds with a structured JSON payload containing the newly created submissionId.

tsxReact / Next.js Client Component Form Handler
'use client';
import { useState } from 'react';

export default function ContactForm({ formId = 'form-contact-demo' }: { formId?: string }) {
  const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle');
  const [submissionId, setSubmissionId] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus('submitting');

    const formData = new FormData(e.currentTarget);
    const payload = {
      ...Object.fromEntries(formData.entries()),
      _gotcha: '',
    };

    const res = await fetch(`https://formfork.io/f/${formId}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
      body: JSON.stringify(payload),
    });

    const data = await res.json();
    if (res.ok && data.success) {
      setSubmissionId(data.submissionId);
      setStatus('success');
      e.currentTarget.reset();
    } else {
      setStatus('error');
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Jane Doe" required />
      <input name="email" type="email" placeholder="jane@company.com" required />
      <textarea name="message" placeholder="How can we help?" required />
      <input type="text" name="_gotcha" style={{ display: 'none' }} tabIndex={-1} autoComplete="off" />
      <button type="submit" disabled={status === 'submitting'}>
        {status === 'submitting' ? 'Sending...' : 'Send Message'}
      </button>
      {status === 'success' && <p>Submitted! Reference ID: {submissionId}</p>}
    </form>
  );
}

3. cURL Command-Line Endpoint Verification

Verify your endpoint configuration, schema validation rules, and webhook triggers directly from your terminal using cURL.

bashcURL JSON Ingestion Request & Expected Response
curl -X POST "https://formfork.io/f/{form_id}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Alex Rivera",
    "email": "alex@enterprise.io",
    "inquiry_type": "Enterprise Partnership",
    "message": "Testing headless form endpoint via cURL",
    "_gotcha": ""
  }'

# HTTP/1.1 200 OK
# {
#   "success": true,
#   "message": "Form submitted successfully",
#   "submissionId": "sub-1729624800-k4m9p"
# }

4. Supported Content-Types & Response Behavior

FormFork automatically inspects incoming Content-Type and Accept headers to determine how to parse the body and format the HTTP response.

Request Content-TypeAccept HeaderUse CaseResponse Format
application/x-www-form-urlencodedtext/html (Default)Standard HTML <form method="POST">302 Redirect or HTML Thank-You Page
application/jsonapplication/jsonReact, Next.js, Vue, Astro fetch()200 OK JSON { success, submissionId }
multipart/form-dataapplication/jsonFile uploads & binary attachments200 OK JSON with attached file metadata

Frequently Asked Technical Questions

Can I submit forms from a static site hosted on Vercel, Netlify, or GitHub Pages?

Yes. FormFork endpoints are designed for static and Jamstack sites. Simply point your HTML form action or fetch() request to https://formfork.io/f/{formId} and add your production domain to the form CORS allowlist if domain restriction is enabled.

How do I prevent page reloads when submitting a form?

Submit the form using JavaScript fetch() and include the header Accept: application/json. FormFork will return a JSON object ({ success: true, submissionId }) instead of performing a browser redirect.

Does FormFork require me to pre-define fields before receiving submissions?

You can either enforce a strict schema created in the Visual Form Studio or submit dynamic key-value fields directly to your endpoint.

All FormFork Documentation Guides

View Full Documentation Index →