Webhooks Guide
Send each form submission to your own server as a JSON POST request. Webhooks are available on the Starter, Premium and Business plans.
How do Formbold webhooks work?
When someone submits your form, Formbold sends an HTTP POST with the submission as JSON to a URL you choose. It happens in real time, so your server doesn't have to poll for new entries.
Use a webhook when you want submissions in your own database, a serverless function or an internal tool. For Slack, Google Sheets or a CRM, the built-in integrations are less work.
How do I add a webhook to my form?
Webhooks live with the other apps on your form's Integrations tab.

- Open your form and click the Integrations tab.
- Find Webhook and click Connect.
- Paste your endpoint. It must be an HTTPS URL, like
https://example.com/api/formbold-webhook. - Choose which submissions to receive (see the next section) and save.
Send a test from the Test Form tab right away and check that your server logged it.
Which submissions does the webhook receive?
The dialog has two checkboxes:
- Receive verified submissions (passed spam check) is on by default. These arrive with
"is_spam": false. - Receive submissions marked as spam is off by default. Turn it on if you want to review or score spam yourself. These arrive with
"is_spam": true.
If you turn both on, always check is_spam in your handler before you act on a submission. Otherwise a bot can end up in your CRM.
What does the webhook payload look like?
Every request has Content-Type: application/json and a body like this:
{
"event": "submission.created",
"form_id": "YOUR_FORM_ID",
"submission_id": "sub_8f2b1a9c3d4e",
"created_at": "2026-09-10T12:00:00.000Z",
"data": {
"name": "Sarah Connor",
"email": "[email protected]",
"message": "Interested in your enterprise solution.",
"budget": "$10,000+"
},
"files": [],
"is_spam": false
}The keys inside data are your form's field names, so a field with name="budget" arrives as data.budget. Rename a field on your site and the key changes too, which is a common way to break a webhook without noticing.
How do I handle the webhook in Node.js with Express?
A minimal Express endpoint looks like this:
import express from "express";
const app = express();
app.use(express.json());
app.post("/api/formbold-webhook", (req, res) => {
const { event, form_id, submission_id, data, is_spam } = req.body;
// Only accept forms you expect
if (form_id !== process.env.FORMBOLD_FORM_ID) {
return res.status(404).end();
}
// Answer quickly, then do the slow work
res.status(200).json({ received: true });
if (is_spam) return;
console.log(`[Formbold] ${event} ${submission_id}:`, data.name, data.email);
// Save to your database, create a ticket, and so on
});
app.listen(3000, () => console.log("Webhook server running on port 3000"));Respond with a 2xx status as soon as you've read the body. If you need to call other APIs or send emails, do it after responding, or push the job to a queue.
How do I secure my webhook endpoint?
Formbold doesn't sign webhook requests, so your endpoint should do its own checks. These are simple and cover most cases:
- Use HTTPS only. Formbold requires it, and it keeps the payload private in transit.
- Make the URL hard to guess. Put a long random value in the path or query string, like
/api/formbold-webhook?key=8f3c..., and reject any request where it doesn't match a value in your environment variables. - Check `form_id`. Accept only the form IDs you expect and ignore the rest.
- Treat `data` as untrusted input. It's whatever a visitor typed. Validate and escape it before you store it or show it in an admin page.
- Respond fast. Return
2xxfirst and do heavy work in the background, so a slow downstream service doesn't hold up the request.
Your API token isn't used for webhooks. Don't put it in the webhook URL.
How do I test webhooks locally with ngrok?
Your laptop isn't reachable from the internet, so use a tunnel:
- Start your local server, for example on port 3000.
- Run
ngrok http 3000. - Copy the HTTPS forwarding URL and add your path, like
https://abc123.ngrok-free.app/api/formbold-webhook. - Paste that URL into the Webhook dialog on the Integrations tab.
- Submit your form and watch the payload arrive in your terminal.
Free ngrok URLs change each time you restart ngrok, so update the webhook URL when they do. If you just want to see the raw request first, a free URL from webhook.site works too.
Last updated: October 19, 2026