# Lead Sources



Every lead carries the source that created it, and the source determines how
much you know before any enrichment runs.

| Source        | Created by                                                               | Identity you start with                      |
| ------------- | ------------------------------------------------------------------------ | -------------------------------------------- |
| `surfaceForm` | A [Surface form](/platform/forms/builder) completion or partial          | Everything they typed, plus the full journey |
| `htmlForm`    | An [external HTML form](/build/webhooks/create-external-form) posting in | Whatever fields you mapped                   |
| `webhook`     | Any system posting to Surface                                            | Whatever you send                            |
| Import        | CSV or `import_leads`                                                    | Whatever the file had                        |

`get_leads_count` with `bySource: true` returns the split. First number to check
when capture looks wrong.

<Note>
  `list_leads` also accepts `source: "website"`. That is de-anonymized visits,
  which is deprecated: no new leads arrive that way, but records created before
  it was retired keep the source.
</Note>

## Surface Forms [#surface-forms]

The richest source: intent as well as identity. Which questions they answered,
where they stopped, how long it took, and the journey before it.

**Partials count.** Someone who typed an email and abandoned at step three is a
lead with a known email and a known objection. See
[Responses](/platform/forms/responses).

## External HTML Forms [#external-html-forms]

For the form you cannot replace. Add the Surface handler and submissions land in
the same leads table, under the `htmlForm` source. See
[External forms](/build/webhooks/create-external-form).

## Webhooks [#webhooks]

Anything else: a product event, a partner feed, a chat tool, an event
registration list. Post it, map the fields, and it lands as a lead.
[Webhooks](/build/webhooks/overview)

## Imports [#imports]

`import_leads` over MCP, or a CSV in the app. Imported leads sit beside every
other lead and have their own filter in the leads table.

**Import does not create demand.** A bought list arrives with no behaviour on
it, so the intent half of the [score](/platform/lead-agents/scoring) has nothing
to read.

## Merging [#merging]

The same person often lands on a form, a webhook and a CSV. Those captures merge
into one record rather than three half-finished copies, which is what scoring
and routing then read.

Which value wins when two sources disagree on the same field is not published.
See [Enrichment](/platform/leads/enrichment) before you build a process on an
assumed precedence order.

<Warning>
  Free-provider emails (`gmail.com`, `outlook.com`) have no company domain to
  resolve, so the fit half of the score has little to work with. Segments can
  filter on `Email type is Business`, which is the fastest way to see how much of
  your capture is personal addresses. If it is a lot, ask for a company domain in
  the form.
</Warning>
