Webhooks logo

Write new leads straight into your own database

Each lead capture submission reaches your endpoint as JSON and becomes a row in your own leads table, seconds after it is sent.

When this happens

New submission on your lead capture form

Do this

POST the submission JSON to your /webhooks/leads endpoint, which validates the payload and inserts a row into your leads table

One-directional. A submission triggers the action — nothing is written back into your form.

A lead is worth most in the minute it arrives, and a startup running its own CRM has nowhere useful to put one until the row exists. This flow sends each submission as a JSON POST to an endpoint you own, so the contact is written to your leads table before anyone opens a notification.

It suits a small engineering team that would rather keep a third-party tool out of the path between form and database. Your handler decides what counts as a valid lead, what gets normalised, and which duplicates are merged.

Setting it up

  1. 1

    Publish your lead capture form with Work Email required — a payload with no address gives your handler nothing to key a lead row on.

  2. 2

    Add a route at /webhooks/leads that accepts POST with a JSON body, and have it return 200 before you write any database code.

  3. 3

    Open the form's settings in formformform, enable the outgoing webhook, and paste the full https URL of /webhooks/leads.

  4. 4

    Submit one test lead and log the raw body, so you can read the exact keys the payload uses for Work Email, Company Name and Company Size.

  5. 5

    Write the validation next: return a 4xx when Work Email is missing, and trim and lowercase Company Name before you compare it against existing rows.

  6. 6

    Insert the row inside a transaction, keyed on Work Email, so a second submission from the same person updates the contact rather than duplicating it.

  7. 7

    Store "What problem are you trying to solve?" in a text column rather than an enum — it is free text and will not fit a fixed set of values.

  8. 8

    Return 2xx only after the commit succeeds, so a failed insert is recorded as a failed delivery instead of disappearing quietly.

What maps where

Using the Lead Generation Form as the starting point. These are its real fields — swap in your own and the mapping works the same way.

Form fieldWebhooks
Work Emailemail column, the unique key on your leads table
Full Namename column on the lead row
Company Namecompany column, normalised before insert
Company Sizesegment column, mapped to your own bands
How did you hear about us?source column on the lead row
What problem are you trying to solve?notes text column on the lead row

Variations worth knowing

Keep the raw payload as well as the row

Insert the whole JSON body into a payloads table with a received-at timestamp before you parse anything. When a lead looks wrong three weeks later you can read what actually arrived rather than guessing at your own parser. It also lets you replay a batch after a schema change without asking anyone to fill the form in again.

Route the largest companies differently

Branch inside the handler on Company Size: the top bands are inserted with an owner already set and a row on your assignments table, everything else lands unassigned. Doing the branching in code rather than in the form keeps the routing rules in one place, so sales can change the bands without anyone republishing the form.

If something isn't arriving

The endpoint receives nothing after a test submission.

Check that the URL saved in the form's settings is the full https address of the route, with no typo in the path, and that the route accepts POST rather than only GET. A server that answers on / but 404s on /webhooks/leads is a failed delivery, not a missing one.

Rows are inserted twice for the same person.

The connection runs one way, so nothing is written back to the form to mark a submission as processed — your database has to own that. Put a unique constraint on the email column and upsert on conflict, or store the submission id from the payload and ignore one you have already seen.

Frequently asked questions

What does the JSON body actually look like?

It carries the form's fields and the values submitted for them. Rather than coding against a shape you have guessed at, send one test lead and log the raw body, then write your parser against the exact keys that arrived. The shape is the same on every submission of that form.

Can my endpoint write anything back into the form?

No. The submission is posted out and nothing is read back beyond the HTTP status your route returns. There is no two-way sync, so a lead score or an owner your database works out stays in your database. Anything the respondent should see has to be on the form itself.

Do I need Zapier for this?

No. Webhooks are native: enable the outgoing webhook in the form's settings, paste your URL, and the POST goes straight from formformform to your server. Zapier is only worth adding when the destination is an app you do not run yourself.

Related automations

Build the form first

The automation needs somewhere to fire from. Publish a form, connect it once, and every submission from then on runs this flow.

Start free