Form Submissions

Public, throttled endpoints that let any frontend post a form submission without API credentials.

Endpoints

GET /api/v1/forms/{formSlug}
POST /api/v1/forms/{formSlug}/submit (throttle: 5/min/IP)

No API key required. The submit endpoint is rate-limited to 5 requests per minute per IP.

Get the form schema

Used by frontends to render the form dynamically.

GET /api/v1/forms/contact-us

200 OK
{
  "data": {
    "name": "Contact Us",
    "slug": "contact-us",
    "fields": [
      { "name": "name",    "label": "Name",    "type": "text",     "required": true,  "max": 120 },
      { "name": "email",   "label": "Email",   "type": "email",    "required": true               },
      { "name": "subject", "label": "Subject", "type": "select",   "required": true,
        "options": ["Sales", "Support", "Other"] },
      { "name": "message", "label": "Message", "type": "textarea", "required": true,  "max": 5000 },
      { "name": "_company", "type": "honeypot" }
    ],
    "success_message": "Thanks — we'll be in touch soon."
  },
  "error": null
}

Submit

POST /api/v1/forms/contact-us/submit
Content-Type: application/json

{
  "name":    "Ada Lovelace",
  "email":   "ada@example.com",
  "subject": "Sales",
  "message": "Tell me about your enterprise plan.",
  "_company": ""
}

201 Created
{
  "data": {
    "id": "01H…",
    "received_at": "2026-05-29T11:30:00Z",
    "message": "Thanks — we'll be in touch soon."
  },
  "error": null
}

Spam & abuse

Validation

Validation rules are derived from the form's field schema. A failed submit returns 422 with per-field details:

422 Unprocessable Entity
{
  "data": null,
  "error": {
    "code":    "VALIDATION_FAILED",
    "message": "The given data was invalid.",
    "details": {
      "email":   ["The email field must be a valid email address."],
      "message": ["The message field is required."]
    }
  }
}

Inactive forms

If the form has is_active = false, the endpoint returns 410 Gone:

410 Gone
{ "data": null, "error": { "code": "FORM_INACTIVE", "message": "This form is no longer accepting submissions." } }

Side effects of a successful submit

Example: HTML form

<form id="contact" action="/api/v1/forms/contact-us/submit" method="post">
  <input  name="name"     type="text"  required />
  <input  name="email"    type="email" required />
  <select name="subject"  required>
    <option>Sales</option><option>Support</option><option>Other</option>
  </select>
  <textarea name="message" required></textarea>
  <input  name="_company" type="text"  tabindex="-1" autocomplete="off"
          style="position:absolute; left:-9999px" />
  <button type="submit">Send</button>
</form>