splitforms.com

Feature · Webhooks

Form webhooks — real-time POST to any URL on every submission

Pipe submissions into your CRM, Slack bot, Postgres, or homemade Lambda — anywhere that speaks HTTP. Signed payloads, auto-formatted chat delivery, per-webhook delivery status in the dashboard.

  • 500 free / mo
  • No credit card
  • 30-sec setup
splitforms webhooks — Pipe submissions into your CRM, Slack bot, Postgres, or homemade Lambda — anywhere that speaks HTTP. Signed payloads, auto-formatted chat delivery, per-webhook delivery status in the dashboard.

No backend to build

Your form posts to one splitforms endpoint — no server, API route, or SDK. splitforms is the backend.

Straight to your dashboard

Every submission is saved to a searchable dashboard and emailed to you — spam filtered before it lands.

Webhooks, built in

No glue code, no third-party middleman — it ships as part of splitforms and works from your first submission.

Copy-paste ready

Drop this into any project.

Replace YOUR_ACCESS_KEY with the key from your splitforms dashboard. No SDK to install, no build step — the same ts you already write.

Generate access key
webhooks.ts
// Add this URL inside your splitforms dashboard → Form → Webhooks.
// Every submission will POST a JSON body to this endpoint within ~1s.

// ─── Example: Next.js 14 App Router route handler ───────────────────
import { NextRequest, NextResponse } from "next/server";
import crypto from "node:crypto";

const SECRET = process.env.SPLITFORMS_WEBHOOK_SECRET!;

export async function POST(req: NextRequest) {
  // 1. Read the RAW body (do not JSON.parse before verifying)
  const raw = await req.text();
  // Header format: "sha256=<hex hmac of the raw body>"
  const sig = req.headers.get("x-splitforms-signature") ?? "";

  // 2. Verify HMAC-SHA256 signature in constant time
  const expected =
    "sha256=" + crypto.createHmac("sha256", SECRET).update(raw).digest("hex");
  const ok =
    sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  if (!ok) return NextResponse.json({ error: "bad signature" }, { status: 401 });

  // 3. Parse and use the payload
  const payload = JSON.parse(raw) as {
    event: "submission.created";
    submission: {
      id: string;
      form_name: string | null;
      data: Record<string, unknown>; // your form fields, key → value
      ip_address: string | null;
      referer: string | null;
      created_at: string;            // ISO 8601, UTC
    };
  };

  await sendToCRM(payload.submission.data);

  // 4. Reply 2xx within 8s — the request is aborted after that, and a
  //    failed delivery is recorded in the dashboard (not auto-retried).
  return NextResponse.json({ ok: true });
}

// ─── Minimal Express equivalent ─────────────────────────────────────
// app.post("/webhooks/splitforms",
//   express.raw({ type: "application/json" }),
//   (req, res) => { /* same verify + handle */ });

How to set it up

How to set up Webhooks.

How webhooks flows through splitforms — what you do, what we do, and what lands in your inbox.

Add a webhook URL in the dashboard

Open Form → Integrations → Webhooks → New webhook. Paste any HTTPS URL (HTTP works in development with a localhost tunnel like ngrok). Each webhook gets its own signing secret displayed once on creation — copy it into your env file as SPLITFORMS_WEBHOOK_SECRET.

Receive a signed JSON payload on every submission

Within ~1 second of submission, splitforms POSTs Content-Type: application/json to your URL with { event: 'submission.created', submission: { id, form_name, data, ip_address, referer, created_at } } — data holds your form fields. The X-Splitforms-Signature header is 'sha256=' followed by the hex HMAC-SHA256 of the raw request body. Verify with constant-time comparison BEFORE parsing, then return any 2xx within 8 seconds.

Check delivery status from the dashboard

Each webhook shows its last-triggered time, last HTTP status, and last error (if any) right in the dashboard, so you can spot a broken endpoint immediately. Delivery gets one attempt with an 8-second timeout and no automatic retry, so make sure your endpoint responds quickly and reliably.

How webhooks works

How does splitforms handle Webhooks?

splitforms turns every form submission into a signed HTTP POST that lands at any URL you choose, within roughly one second of the user clicking Submit. Add a webhook in the dashboard, and from then on your endpoint receives a JSON payload with the submission fields, the submission id, and a created_at timestamp. Route the same submission to an email inbox or a webhook at the same time — nothing here is one-or-the-other.

  • Sub-second delivery — POST hits your endpoint within ~1 second of submit
  • HMAC-SHA256 signed requests — verify the payload came from splitforms in constant time
  • Auto-detected Slack, Discord, Telegram, and WhatsApp formatting — paste a URL, no relay needed
splitforms webhooks in action

What you get

What do you get with Webhooks?

Every reason below is the boring, reliable kind — the fundamentals of webhooks, built once and tested in production so you never have to.

  • Last delivery status and error shown per webhook right in the dashboard
  • Multiple webhooks per form — fan out to CRM, Slack, Postgres, and Lambda in parallel
  • 8-second delivery timeout — respond fast and offload heavy work to your own queue
Why teams pick splitforms for webhooks

How SplitForms works

From form to workflow in 3 simple steps.

Connect your form, collect every submission, and send data where it needs to go — without building backend infrastructure.

A SplitForms contact form submission launching straight to your inbox

Add your endpoint

Point your form to your unique SplitForms endpoint. That's it.

HTML form pointing at a SplitForms submit endpoint

Receive submissions

We instantly capture and organize every submission in your inbox.

Submissions inbox with searchable leads and status pills

Route anywhere

Send data to email, spreadsheets, CRMs, webhooks, and 7,000+ apps.

Generic integration tiles for email, sheets, chat, CRM, automate, and webhook

No credit card required. Set up in under 60 seconds.

Connect & automate

Connect your favorite tools and automate everything

SplitForms works with the destinations you route to and the platforms you build on — from Slack and Sheets to WordPress, Shopify, and Next.js.

Connect your SplitForms form to Slack, Google Sheets, Mailchimp, Zapier and more

Trusted by indie teams and agencies shipping forms worldwide

PETAL/COKRAFT.DELINEAR-XBUILD.DEVSTUDIO 71MERIDIANFRAME&CO

Testimonials

Loved by developers shipping at every scale.

40 quotes on record — from indie hacks to agency migrations.

Common questions

Webhooks questions.

View all FAQs
How does the splitforms webhook payload work and what fields does it contain?

Every webhook is a POST with Content-Type: application/json. For a generic URL, the body is { event: "submission.created", submission: { id, form_name, data, ip_address, referer, created_at } }, where data holds your form fields as a key-value object. The X-Splitforms-Signature header is 'sha256=' followed by the hex HMAC-SHA256 of the raw request body, computed with the per-webhook secret — use it to verify the request really came from splitforms. There's also an X-Splitforms-Event header (currently always 'submission.created'). If your URL matches a known Slack, Discord, Telegram, or WhatsApp (CallMeBot) endpoint, splitforms detects it and sends that platform's native message format instead of the generic JSON shape.

What plan includes webhooks, and is there a per-event fee?

Webhooks unlock on Pro ($5/month) and above. There is no per-webhook fee, no per-event fee, and no event-volume cap beyond your monthly submission limit. Pro includes 5,000 submissions/month and unlimited forms; Pro ($5/month) and the $59 3-year plan raise the monthly submission cap further. Forms are unlimited on every plan, including Free.

How do I enable a webhook and verify the signature in my code?

Dashboard → your form → Integrations → Webhooks → Add webhook → paste your HTTPS URL → save. Copy the signing secret shown once on creation into your env (e.g. SPLITFORMS_WEBHOOK_SECRET). On your endpoint: read the RAW request body BEFORE JSON.parse (Express needs express.raw(), Next.js gets it via req.text()), compute 'sha256=' + crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex'), and compare to the X-Splitforms-Signature header using crypto.timingSafeEqual. Respond within 8 seconds — deliveries are not currently retried automatically, so a slow or failing endpoint means that submission's webhook delivery is simply marked failed in the dashboard.

Does it work with Next.js, Express, FastAPI, Cloudflare Workers, Lambda, or Supabase Edge Functions?

Yes — webhooks are framework-agnostic since they're just HTTP POSTs. Patterns: Next.js App Router uses route handlers (app/api/webhooks/splitforms/route.ts with req.text() to get raw body). Express needs app.post('/hook', express.raw({ type: 'application/json' }), handler). FastAPI: read request.body() before request.json(). Cloudflare Workers / Lambda / Supabase Edge Functions: use Web standard Request and call .text() before parsing. The signature scheme (raw-body HMAC-SHA256, hex-encoded) is identical everywhere.

My webhook isn't firing or is returning errors — how do I troubleshoot?

Open Dashboard → Form → Webhooks — each webhook row shows its last-triggered time, last HTTP status, and last error message. Common causes and fixes: (1) signature mismatch — you're parsing JSON before reading the raw body, so the hash differs (switch to req.text() / express.raw() and verify against the raw bytes), or you're comparing a bare hex digest against the header, which is 'sha256='-prefixed. (2) Returning non-2xx — a failed delivery is recorded but not currently retried, so make your endpoint reliable; if you intentionally reject a submission, still return 200. (3) Timeout — the request is aborted after 8 seconds; offload heavy work to a queue and respond fast. (4) URL behind auth — splitforms can't pass cookies; use signature verification, not basic auth. (5) Localhost — use ngrok or a tunnel; splitforms can't reach 127.0.0.1. Since there's no automatic retry yet, fix the issue and submit the form again to confirm delivery.

Simple pricing

Start free. Scale when you need more.

Choose a plan that fits your workflow — from a free form endpoint to full automations, exports, and higher submission limits.

Free

$0

Free forever

 
Best for testing

For side projects and indie devs.

  • 500 submissions / mo
  • Unlimited forms
  • Email notifications included
  • Honeypot spam filtering
  • Submissions dashboard
  • MCP setup stays free
  • No credit card required

3-Year

$59/ 36 months
was $99 · save 40% · new-user price

Pay $59. 3 years sorted.

  • 15,000 submissions / mo
  • Unlimited forms
  • Everything in Pro
  • Renews every 3 years
  • Long-term discount
  • Priority support included
  • Vote on the roadmap

No credit card required on Free • Cancel anytime