Six groups of fields: identity, attribution, journey, context, qualification, and a delivery envelope. Identity is the only one most webhooks send. The other five are what turn a row in your CRM into a lead somebody can route, price and attribute — and they are all knowable at the moment the lead is created.
The reason they go missing is structural, not lazy. Your form tool posts the form’s own fields, because the form is all it knows about.
Why does your CRM get a name and an email and nothing else?
Because the thing sending the webhook is the form, and the form never saw the ad click. A form knows its own inputs. The campaign, the referrer, the click ID, the landing page, the three earlier visits — all of that lives in the tracking layer of the browser session, and nothing wires the two together by default.
So the payload that arrives is an echo of the fields on screen: name, email, maybe phone, maybe a dropdown. Then the sales rep asks where the lead came from and nobody can answer, and marketing reports on lead counts because lead counts are the only thing the data supports.
This is the same root cause behind conversions that show up as Direct in your ad platform’s reports. The attribution data existed. It was on the landing URL, in the referrer, in a cookie. Nothing carried it forward to the moment that mattered.
The fix is not a bigger form. Asking the visitor “how did you hear about us?” trades a measurable fact for an unreliable memory and costs you conversion rate to do it. The fix is a payload that carries what the session already knew.
What are the six field groups every lead webhook needs?
Identity, attribution, journey, context, qualification, and the delivery envelope. Each group answers a different question, and each has a different consumer inside your business — which is why cutting any of them produces a specific, predictable complaint two weeks later.
| Field group | What it carries | Who needs it |
|---|---|---|
| Identity | Normalised email, phone in E.164, name, a stable person ID, hashed copies for ad platforms | Sales, dedupe logic, conversion APIs |
| Attribution | utm_source/medium/campaign/content/term, click IDs, landing page, referrer |
Marketing reporting, budget decisions |
| Journey | Session count, first touch, last touch, time to convert, pages before the form | Attribution modelling, sales context |
| Context | Form page URL, form ID, device, browser, country/region/city, timestamps | Routing, troubleshooting, segmentation |
| Qualification | Lead status (partial or completed), fields completed, engagement signals, fit verdict | Prioritisation, SLA rules |
| Envelope | Event ID, event type, schema version, signature, sent-at timestamp | Your receiving endpoint |
Two of these deserve more than a table row.
Identity is where normalisation happens, not where it gets deferred. Send the email lowercased and trimmed, and the phone in E.164 with the country code resolved — not as the visitor typed it. Every downstream system that will ever match this person expects a canonical form: Meta’s Conversions API requires email lowercased with whitespace trimmed and phone as digits only with country code before hashing (Meta, customer information parameters). If your webhook ships " Ava.Chen@Example.com " and (0412) 345 678, you have handed every consumer the same normalisation job and guaranteed they will do it differently.
Attribution is where you decide whether reporting is possible at all. Send the raw UTM parameters and the click IDs separately, never one merged “source” string. A resolved channel name is an opinion; gclid, fbclid, msclkid and ttclid are facts, and they are the only things that will still join to platform data next quarter. If the difference between those identifiers is fuzzy, gclid, fbclid and UTM parameters each answer a different question — and a payload should carry all three kinds.

What does a complete lead webhook payload look like?
Like this — about sixty lines of JSON, flat enough to map onto CRM fields without a transformation script, grouped enough that a human can read it.
{
"event_id": "evt_9f2c1a7b4e",
"event_type": "lead.captured",
"schema_version": "1.2",
"sent_at": "2026-09-20T10:42:18Z",
"occurred_at": "2026-09-20T10:41:52Z",
"identity": {
"person_id": "ppl_8321fd",
"email": "ava.chen@example.com",
"phone": "+61412345678",
"first_name": "Ava",
"last_name": "Chen",
"email_sha256": "a3f1…",
"phone_sha256": "7c02…"
},
"attribution": {
"utm_source": "facebook",
"utm_medium": "paid_social",
"utm_campaign": "spring-retarget",
"utm_content": "video-15s-b",
"click_ids": { "fbclid": "IwAR2…", "gclid": null },
"landing_page": "https://example.com/demo?utm_source=facebook",
"referrer": "https://l.facebook.com/"
},
"journey": {
"sessions": 3,
"first_touch": { "source": "google", "medium": "organic", "at": "2026-09-14T08:12:03Z" },
"last_touch": { "source": "facebook", "medium": "paid_social", "at": "2026-09-20T10:39:41Z" },
"time_to_lead_seconds": 528495
},
"context": {
"form_page": "https://example.com/demo",
"form_id": "demo-request",
"device": "mobile",
"browser": "Safari",
"country": "AU",
"region": "NSW",
"city": "Sydney"
},
"qualification": {
"status": "partial",
"fields_completed": ["email", "phone", "company"],
"last_field": "company",
"dwell_seconds": 74
}
}
Three things about this shape are worth copying. Timestamps are separate: occurred_at is when the lead happened, sent_at is when you posted it, and a retry changes only the second one. Nulls are explicit rather than omitted, so the receiver can tell “no gclid” from “field not implemented yet”. And the hashed identity copies sit beside the plaintext ones, so a downstream conversion API can use them without re-implementing the hashing rules.
Which fields does sales use, and which are for reporting?
Sales uses identity, qualification and a two-line journey summary. Reporting uses attribution and context. Conversion APIs use the hashed identity fields and the click IDs. They are genuinely different audiences, and the common failure is designing the payload for one of them.
A rep opening a lead record wants to know who this is, how warm they are, and what they were looking at. Campaign taxonomy is noise at that moment — but “third visit, came back from a Meta ad, filled everything except company” changes how the call opens.
Marketing wants the opposite: the identity fields are irrelevant in aggregate, and the UTM and click ID fields are the entire report. If those arrive inconsistently — sometimes in a merged source string, sometimes missing on mobile — every source-level number is quietly wrong.
The qualification group is the one that serves both. A lead status of partial versus completed is an operational fact, and a partial lead is a real, contactable lead rather than a failed submission — but only if the status travels with the record. Send it as its own field, never as a magic value inside a notes string.
How do you make lead webhook delivery reliable?
Four things: a stable event ID, at-least-once delivery with retries, a signature, and a receiver that is idempotent. Delivery is the half of webhook design that nobody specifies until the day the CRM has three copies of the same person.
Give every event a deterministic ID. Derive it from the record it describes — not a random UUID per attempt — so the same lead produces the same event_id on the first send and on the retry an hour later. This is the same pattern conversion APIs use to collapse duplicate events: Meta deduplicates browser and server events that share an event ID and event name (Meta, deduplicate pixel and server events). Your CRM deserves the same protection.
Retry, with backoff, and keep the failures visible. A webhook endpoint returning a 502 for ten minutes should not cost you ten minutes of leads. Retry on connection errors, timeouts and 5xx responses; do not retry a 400, because the payload will still be malformed next time. Whatever exhausts its retries needs to land somewhere a human looks, otherwise “we send a webhook” quietly becomes “we send most leads”.
Sign the payload. An HMAC signature over the raw body, computed with a shared secret and sent as a header alongside the timestamp, lets the receiver verify both origin and integrity. A webhook endpoint that accepts anything posted to a guessable URL is an open door into your CRM.
Make the receiver idempotent anyway. At-least-once delivery means duplicates are normal, not exceptional. Store the event_id on receipt and drop anything you have already processed. This is cheap to build on day one and painful to retrofit after a bad week.
What should you never put in a lead webhook payload?
Secrets, sensitive-category data, and anything you cannot explain the lawful basis for. A webhook body travels to a system you do not control and lands in logs you will never audit, so the contents deserve the same scrutiny as a public API response.
Never put an API key, session token or password in the body. Credentials belong in headers, rotated separately from the schema. Never include the raw values of sensitive form fields — health details, financial specifics, government identifiers — just because they happen to be on the form.
Do not send fields you have no use for on the receiving end. The honest inventory of what a tracking tag actually collects is broader than most teams assume, and forwarding all of it to a CRM turns a marketing integration into a data-retention problem nobody scoped.
And do not send unbounded free text. A comments field with no length cap is how one visitor’s paste breaks an integration for everyone.
How does PartialLeads fill in a lead webhook payload?
By owning the layer the form never sees. PartialLeads captures email and phone as they are typed — before the visitor hits submit — and keeps them on a session record that already carries the UTMs, click IDs, landing page, referrer and geo from the visit that started it. That is partial lead capture: the field-level capture and terminal flush that produce a contactable record even when the submit button is never pressed.
Identity arrives normalised, not raw. Email is lowercased and trimmed; phone is converted to E.164, with the country code resolved from the session’s geo when the visitor typed a local-format number. The same canonical builder feeds the hashed copies used by the server-side conversion APIs, so the value your CRM sees and the value Meta scores are derived from one normalisation, not two.
The journey group comes from the identity cluster rather than the current session. PartialLeads unions a person’s sessions across six tiers — visitor ID, email, phone, IP and user-agent, device fingerprint, and shared click ID — which is how visitor identity resolution works in practice, and it is why the record can say “three sessions, first touch Google organic, last touch Meta” instead of treating each visit as a stranger.

Qualification is a field, not an inference. Every lead carries a Partial or Completed status, and where AI qualification is switched on, a match verdict and confidence from scoring the lead against your ideal customer sit alongside it — so routing rules can act on fit, not just on arrival order.
When a purchase later matches back to that person, the same pipeline fans the conversion out server-side to Meta, Pinterest, TikTok and Google Ads, plus your own CRM webhook, from one deterministic event ID — so a redelivered webhook cannot double-count the sale.
The honest constraint: the payload is only as complete as the visit. A lead who arrives with no UTMs, no click ID and a blank referrer has an attribution group full of nulls, and no system invents what the browser never sent. The journey and identity groups are what recover that case — not a guessed source.
| What breaks | The mechanism | Where you see it in the dashboard |
|---|---|---|
| CRM receives a name and email with no source | Session-level capture of UTMs, click IDs, landing page and referrer, carried onto the lead record | Leads list — UTM column beside each lead |
| The lead abandoned before submit, so nothing fires | Field capture on input with a terminal flush before the page unloads | Leads list — Partial status badge |
| Each visit looks like a different person | Six-tier identity cluster unions sessions into one person | Leads list — Journey column, “N sessions” label |
| Email and phone arrive in inconsistent formats | Email lowercased and trimmed, phone normalised to E.164 with geo country fallback | Lead detail — normalised contact fields |
| Sales cannot tell which leads to call first | Partial or Completed status plus AI match verdict and confidence | Lead Intelligence — Customer Match card |
| A redelivered event double-counts a conversion | Deterministic event ID with a unique dedup table per config | CAPI activity log — one row per event |
Recover the leads you're already earning
Tell us what you're trying to track or fix. We'll show you which visitors your forms miss — and how PartialLeads recovers and qualifies them.
Sources
https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events https://developers.facebook.com/docs/marketing-api/conversions-api/using-the-api