Docs
API & Developers

Webhooks & Events

FormsIntel broadcasts sanitized JSON payloads instantly to your webhook URLs the microsecond a human submission safely bypasses our velocity filters.

The Pre-Webhook Pipeline

FormsIntel ensures you never receive junk data.

  1. Submission Received — User hits submit on your frontend.
  2. Validation Phase — We check required fields and data types based on your schema.
  3. Spam AI Isolation — The submission passes through the Honeypot check and Sub-Second Velocity Monitor.
  4. Decision — If it's a bot, the submission is siloed into the Spam Dashboard and the webhook is aborted.
  5. Dispatch — If it's a human, the JSON payload is dispatched to your webhook URL immediately.

Structured POST Payload

Webhooks are sent as POST requests with a Content-Type: application/json header.

json
{
  "formId": "ff_form_xyz123",
  "submissionId": "sub_658af032e52b2",
  "data": {
    "name": "Jane Smith",
    "email": "jane@example.com",
    "message": "I would like to upgrade my plan."
  },
  "telemetry": {
    "ipAddress": "122.161.49.200",
    "completionSeconds": 4.8,
    "isSpam": false,
    "location": {
      "city": "New York",
      "country": "US"
    }
  },
  "submittedAt": "2026-05-18T10:04:12.809Z"
}

Setting up a Node.js Express Receiver

Here is an example of how to receive and process a FormsIntel webhook in a standard Express.js environment.

javascript
const express = require('express');
const app = express();

// Required to parse JSON payloads
app.use(express.json());

app.post('/api/webhooks/formsintel', (req, res) => {
  const { formId, data, telemetry } = req.body;

  // Verify the payload exists
  if (!formId || !data) {
    return res.status(400).send('Invalid payload structure');
  }

  console.log(`New submission received for form ${formId}!`);
  console.log(`User Email: ${data.email}`);
  console.log(`Completion Time: ${telemetry.completionSeconds}s`);

  // TODO: Trigger your internal workflows (e.g., send an email, update CRM)

  // You MUST return a 200 OK status to acknowledge receipt
  // Otherwise, FormsIntel will consider the delivery failed
  res.status(200).send('Webhook received');
});

app.listen(3000, () => console.log('Webhook receiver running on port 3000'));

SSRF Protection

For security, FormsIntel validates all webhook URLs before dispatch to prevent Server-Side Request Forgery (SSRF) attacks against our infrastructure.

  • Private/Local IP ranges (127.0.0.1, localhost, 10.x.x.x, 192.168.x.x) are strictly blocked.
  • URLs must use standard ports (80, 443).
  • If you need to test webhooks locally, use a secure tunneling service like ngrok to expose your local port to a public URL.
Roadmap
  • HMAC Payload Signing — We are adding cryptographic signatures to headers so you can verify the payload definitively originated from FormsIntel servers.
  • Automatic Retry (Exponential Backoff) — If your server returns a 5xx error or times out, we will automatically retry sending the payload 5 times over 24 hours to ensure zero data loss.
  • Webhook Delivery Logs — View the HTTP status codes of all historical webhook dispatches directly in the Dashboard.