Skip to content

Inbound

Web forms

Keep your own form design and still use Nextora’s form engine. Post submissions to a Nextora form: it validates them, stores them, creates a lead and runs the form’s automations — without an API key in your web page.

Auth
None — public endpoint
CORS
Any origin
Plan
Every plan

How it works

  1. Build the form in Nextora: its fields, required answers, what it creates (a lead by default; or a contact, a task, or nothing) and how answers map to record fields. Activate it.
  2. Fetch its definition once for the field IDs.
  3. From your page or server, submit the answers keyed by field ID.

Answer formats

Field typeAnswer
text, textarea, email, phone, hiddenA string. Emails and phone numbers are validated.
number, rating, scale, npsA number within the field’s range.
dateA string, YYYY-MM-DD.
checkboxtrue or false.
dropdown, radioOne option value from the definition.
multiselectAn array of option values.
addressAn object with street, line2, city, region, postal_code and country.
file, booking, signatureUse the hosted form or its embed: they need an upload or a booking step.

From a web page

The endpoint accepts requests from any origin, so a static site can post to it directly. Name your inputs after the field IDs and send them as data:

HTML
<form id="contact">
  <input name="1c3e5a7b-9d1f-4b3d-8e5f-7a9c1e3b5d10" required placeholder="Full name">
  <input name="3e5a7c9d-1f3b-4d5f-9a7b-9c1e3a5d7f21" type="email" required placeholder="Work email">
  <button>Send</button>
</form>

<script type="module">
  const form = document.querySelector('#contact');
  form.addEventListener('submit', async event => {
    event.preventDefault();
    const response = await fetch('https://acme.nextora.co/api/forms/e3f5a7c9-1b3d-4f5a-8c7e-9b1d3f5a7c08/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        data: Object.fromEntries(new FormData(form)),
        request_id: crypto.randomUUID(),
        source_url: location.href,
      }),
    });
    form.replaceChildren(response.ok ? 'Thanks — we will be in touch.' : 'Something went wrong. Please try again.');
  });
</script>

Spam protection and limits

  • Each form accepts 10 submissions a minute from one IP address; more are refused with 429 and a Retry-After header.
  • When the form uses reCAPTCHA v3 or hCaptcha, send the widget’s token as captcha_token; without it the submission is refused with captcha_required.
  • Password-protected forms need the access token from their unlock step in the X-Form-Access header.
  • Answers may total up to 500 KB.

Get a form

GET/api/forms/{form_id}

Public. Only active forms are returned.

Returns the form’s title, description and fields — with the IDs to key answers by — plus its public settings and branding.

Path parameters

  • form_iduuidRequired

    The form’s ID, from its share link or embed code.

Returns

The form definition, not wrapped in data. 404 when the form does not exist or is not active.

GET/api/forms/{form_id}
curl https://acme.nextora.co/api/forms/e3f5a7c9-1b3d-4f5a-8c7e-9b1d3f5a7c08
Response200 OK
{
  "id": "e3f5a7c9-1b3d-4f5a-8c7e-9b1d3f5a7c08",
  "title": "Talk to sales",
  "description": "Tell us about your team and we will be in touch within a working day.",
  "fields": [
    {
      "id": "1c3e5a7b-9d1f-4b3d-8e5f-7a9c1e3b5d10",
      "type": "text",
      "label": "Full name",
      "required": true,
      "position": 0
    },
    {
      "id": "3e5a7c9d-1f3b-4d5f-9a7b-9c1e3a5d7f21",
      "type": "email",
      "label": "Work email",
      "required": true,
      "position": 1
    },
    {
      "id": "5a7c9e1f-3b5d-4f7a-8b9d-1e3a5c7f9b32",
      "type": "text",
      "label": "Company",
      "required": false,
      "position": 2
    },
    {
      "id": "7c9e1a3b-5d7f-4a9c-9d1f-3a5c7e9b1d43",
      "type": "dropdown",
      "label": "Team size",
      "required": false,
      "position": 3,
      "options": [
        {
          "value": "1-10",
          "label": "1–10"
        },
        {
          "value": "11-50",
          "label": "11–50"
        },
        {
          "value": "51+",
          "label": "51 or more"
        }
      ]
    },
    {
      "id": "9e1a3c5d-7f9b-4c1e-8f3a-5c7e9a1d3f54",
      "type": "textarea",
      "label": "What do you want to improve?",
      "required": false,
      "position": 4
    }
  ],
  "is_active": true
}

Submit a form

POST/api/forms/{form_id}/submit

Public. Requests from browsers on any origin are allowed.

Validates the answers, stores the submission, creates the record the form is set up to create, and runs its automations — the same as a submission of the hosted form.

Path parameters

  • form_iduuidRequired

    The form’s ID.

Body parameters

  • dataobjectRequired

    Answers keyed by field id, in the formats above.

  • Makes retries safe: a repeat with the same ID and answers returns the first receipt with replayed: true; different answers are 409 submission_conflict.

  • The page the form was on.

  • The CAPTCHA token, when the form uses one.

  • gclidstring

    Ad click IDs for conversion tracking: gclid, gbraid, wbraid and fbclid are accepted.

Returns

A receipt with the submission ID and the records created.

POST/api/forms/{form_id}/submit
curl -X POST https://acme.nextora.co/api/forms/e3f5a7c9-1b3d-4f5a-8c7e-9b1d3f5a7c08/submit \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "1c3e5a7b-9d1f-4b3d-8e5f-7a9c1e3b5d10": "Grace Whitfield",
      "3e5a7c9d-1f3b-4d5f-9a7b-9c1e3a5d7f21": "[email protected]",
      "5a7c9e1f-3b5d-4f7a-8b9d-1e3a5c7f9b32": "Harbor Logistics",
      "7c9e1a3b-5d7f-4a9c-9d1f-3a5c7e9b1d43": "11-50",
      "9e1a3c5d-7f9b-4c1e-8f3a-5c7e9a1d3f54": "One queue for customer email and WhatsApp."
    },
    "request_id": "2f4a6c8e-0b2d-4f6a-8c0e-2b4d6f8a0c13",
    "source_url": "https://www.example.com/contact"
  }'
Response200 OK
{
  "success": true,
  "submission_id": "8b0d2f4a-6c8e-4a0b-9d2f-4a6c8e0b2d35",
  "created_entity_type": "lead",
  "created_entity_id": "a7c9e1b3-5f2d-4a6c-8e9b-2d4f6a8c0e13",
  "lead_id": "a7c9e1b3-5f2d-4a6c-8e9b-2d4f6a8c0e13",
  "contact_id": null,
  "task_id": null,
  "request_id": "2f4a6c8e-0b2d-4f6a-8c0e-2b4d6f8a0c13"
}

Form errors carry a code, often a readable error, and field_id when one answer is the problem:

StatuscodeMeaning
400invalid_answerAn answer is missing or invalid; field_id says which.
400captcha_required, captcha_failedSend a valid CAPTCHA token.
404—The form does not exist or is not active.
409submission_conflictThe request_id was used with different answers.
409form_changedThe form changed during the submission; fetch it again.
429rate_limitedToo many submissions; wait for Retry-After seconds.
503submission_unavailableTry again shortly.