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.
New submission on your lead capture form
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
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
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
Open the form's settings in formformform, enable the outgoing webhook, and paste the full https URL of /webhooks/leads.
- 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
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
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
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
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 field | Webhooks |
|---|---|
| Work Email | email column, the unique key on your leads table |
| Full Name | name column on the lead row |
| Company Name | company column, normalised before insert |
| Company Size | segment 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
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.
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
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.
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
- Deliver job applications to your hiring service
Every application is posted as JSON to your applicant tracking service, which validates the fields before it creates a candidate.
- Fan event sign-ups out to your own services
One POST per RSVP writes the attendee to your database and publishes a message the rest of your services can listen for.
- Push support requests onto your own job queue
Every support submission is posted to an endpoint that enqueues the request and sets its priority from the answer on the form.
- Send custom orders to your fulfilment backend
Each order submission is posted to your orders API, which records the items and starts fulfilment with nothing rekeyed by hand.
- Stream feedback scores into your analytics pipeline
Each NPS response is posted to an ingestion endpoint that normalises the score and streams the record into your warehouse.
- Deliver a lead magnet with a Kit sequence
An ebook request drops the reader into a Kit sequence that sends the download link and nurtures from there.
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