Jotform Webhooks: A Complete Setup Guide for Developers
If you need Jotform submissions to hit your own backend — a CRM you built, a database, a custom workflow — webhooks are the fastest path. Here's how to set them up, parse the payload, and handle the edge cases Jotform's UI doesn't warn you about.
- Webhooks are configured per-form under Settings → Integrations → Webhooks.
- The payload is multipart/form-data with a 'rawRequest' JSON field that contains the submission.
- Jotform does not retry failed webhooks aggressively — if your endpoint 500s, the delivery is lost.
- For anything business-critical, queue the webhook at your edge and process async — don't do heavy work in the webhook handler itself.
Webhooks are Jotform's escape hatch. If Zapier doesn't have the integration you need, if your CRM is homegrown, if you need to do something custom when a form is submitted — a webhook posts the submission to your URL in real time. Simple in concept. Full of small traps in practice.
I was on the Jotform engineering team for five years. This guide covers webhook setup and the parts that aren't well documented — payload shape, retry behavior, and the edge cases that fail silently in production.
Setting up a webhook
In the Form Builder:
- Open the form → Settings → Integrations.
- Search 'Webhooks' and select it.
- Paste your endpoint URL (must be HTTPS; HTTP endpoints are rejected).
- Save. Submit a test entry to your form and check the logs at your endpoint.
Jotform will start sending submissions to your URL immediately. There's no signature verification built in by default — if you need to verify the source, see the 'Verifying the source' section below.
What the payload looks like
Jotform sends webhooks as multipart/form-data POST requests. The key field to parse is 'rawRequest' — it's a JSON-encoded string containing the full submission. There are also top-level fields with submission metadata.
Top-level form fields
- formID — the form's numeric ID
- submissionID — the submission's numeric ID
- formTitle — the form title
- ip — respondent's IP address
- rawRequest — JSON string with the submitted field values
Parsing rawRequest
The rawRequest field is a JSON string. Keys look like 'q3_yourName' — the number is the field's ID in the form, and the suffix is a slugified label. Values are strings, or nested objects for multi-part fields (name with first/last, address with street/city/state).
// Node.js / Express example
app.post('/jotform-webhook', (req, res) => {
const submission = JSON.parse(req.body.rawRequest);
const name = submission.q3_yourName; // { first: 'Buri', last: 'Ilter' }
const email = submission.q4_email;
const message = submission.q5_message;
// Process async — don't block the webhook response
queue.push({ formID: req.body.formID, submission });
res.status(200).send('ok');
});Verifying the source
Jotform doesn't sign webhook requests by default, which means anyone who knows your endpoint URL can POST to it. If your handler writes to a database or triggers a workflow, you need a verification step.
Option 1: Shared secret in the URL
Include a random token in the webhook URL: 'https://yoursite.com/webhook?token=xyz'. Your handler checks the token before processing. Low-effort, decent for most cases. Downside: the token leaks if the URL is ever logged anywhere.
Option 2: Form ID + IP allowlist
Verify that the formID in the payload matches the form you expect, and (optionally) that the request comes from Jotform's IP range. More work but more robust.
Option 3: Jotform API for cross-check
On receiving the webhook, call the Jotform API with the submissionID to re-fetch the submission. If the API confirms it exists, the webhook is real. Adds latency but eliminates spoofing. Good for high-stakes workflows (payments, HIPAA).
Retries and delivery guarantees
This is the part of Jotform webhooks that's least documented and most likely to bite. Jotform's webhook retry policy is minimal: if your endpoint returns a non-2xx response or times out, Jotform retries a small number of times and then gives up. There's no dead-letter queue exposed to you.
In practice, this means: if your endpoint is down for five minutes during deploy, you'll lose those submissions. The fix is to not rely on webhook delivery alone for business-critical data. Best pattern:
- Your webhook handler writes the raw payload to durable storage (database, queue) immediately.
- A separate worker processes the payload from storage.
- A nightly job calls the Jotform API and reconciles against your storage — any submissions that arrived in Jotform but not in your DB are re-processed.
For most non-critical workflows (a lead notification, a Slack message), the simple 'respond 200 fast, process async' pattern is enough. For anything where missing a submission costs money or breaks compliance, add the reconciliation step.
Edge cases
File uploads
If your form has file upload fields, the webhook payload contains URLs to the uploaded files — not the files themselves. Jotform hosts the files at those URLs and they're accessible without authentication by default. If the file is sensitive, either move it to your own storage on receipt or enable Jotform's 'private submissions' setting.
Multi-select field formatting
Checkboxes with multiple selected values come through as JSON arrays in rawRequest, but as comma-separated strings in some legacy payloads. Write your parser to handle both — trim whitespace, split on comma if string, iterate if array.
Updated submissions
If a respondent edits their submission (via an edit link), Jotform fires the webhook again with the updated data. Your handler needs to be idempotent — processing the same submissionID twice shouldn't double-book, double-charge, or double-create.
Test submissions
Jotform's 'Preview' mode doesn't fire webhooks. You have to publish the form and submit through the live URL to test. Use a test webhook URL (webhook.site, ngrok, RequestBin) for iteration, then switch to production once the parsing works.
Webhooks vs Zapier vs native integrations
The question I get asked most: when do I use a webhook vs Zapier vs a direct integration?
- Native Jotform integration (Salesforce, QuickBooks, HubSpot, Stripe) — use when the integration exists and covers your workflow. Fastest, no code, maintained by Jotform.
- Zapier — use when you need to connect to a tool Jotform doesn't integrate with natively, and Zapier does. Low-code, good error handling, costs per Zap run.
- Webhook — use when you need a custom backend action, control over retry logic, or the throughput doesn't justify Zapier's per-run cost. Requires engineering.
Next step
If you want the webhook + backend wiring handled end-to-end (including the reconciliation step), that's the kind of custom work I do in a done-for-you engagement. Or if you just want to know whether a webhook is the right call for your setup, book a free 20-minute call.