> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.dealsignal.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.dealsignal.com/_mcp/server.

# Lead Enrichment Overview

> Submit a bulk list of contacts; receive verified emails, phones, titles, and company data.

**Lead Enrichment (LE)** is Dealsignal's asynchronous bulk-enrichment product. You submit a list of contacts in a columnar format, Dealsignal matches each row against its verified B2B database, runs the enrichment pipeline, and returns paginated results.

A single LE job can process from a handful to tens of thousands of leads. The pipeline runs in the background — poll status or use a webhook.

---

## Lifecycle

### Create the job

`POST /api/v1/lead_enrichments` with your lead data. The response includes the job `id`.

### Poll status (or wait for the webhook)

`GET /api/v1/lead_enrichments/{id}`. The job moves through `Created → Launched → Running → Completion Running → Completed`. It is finished when `is_completed` is `true` (`completed_at` is then set).

### Fetch paginated results

`GET /api/v1/lead_enrichments/{id}/final_result` with `page` and `page_size`. Pages are zero-based; the default size is 100. Call it once `is_completed` is `true` — before that it returns a `message` instead of results.

---

## Quickstart

### Submit a job

```bash
curl -X POST "https://app.dealsignal.com/api/v1/lead_enrichments?api_key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "lead_enrichments": {
      "name": "YOUR_UNIQUE_JOB_NAME",
      "source_type": "from_json",
      "match_field": "linkedin_url",
      "contact_profile_only": true,
      "lead_data": {
        "keys": ["first_name", "last_name", "company_name", "linkedin_url", "unique_identifier"],
        "values": [
          ["Jane", "Smith", "Acme Corp",  "https://www.linkedin.com/in/jane-smith-example", "1"],
          ["John", "Doe",   "Globex Inc", "https://www.linkedin.com/in/john-doe-example",   "2"]
        ]
      }
    }
  }'
```

### Poll until complete

```bash
curl -H "Accept: application/json" \
  "https://app.dealsignal.com/api/v1/lead_enrichments/{id}?api_key=YOUR_API_KEY"
```

```json
{
  "lead_enrichment": {
    "id": 652,
    "name": "YOUR_UNIQUE_JOB_NAME",
    "status": "Completed",
    "is_completed": true,
    "completed_at": "2024-06-01T11:30:00Z",
    "type": "linkedin_url",
    "profile_type": "Contact Profile",
    "total_leads_to_enrich": 2,
    "total_enriched_leads": 2
  }
}
```

The job is wrapped in `lead_enrichment`. The response carries more keys than shown; see the [API Reference](/api-reference/lead-enrichment/get-lead-enrichment-job) for the documented ones.

### Fetch results

```bash
curl -H "Accept: application/json" \
  "https://app.dealsignal.com/api/v1/lead_enrichments/{id}/final_result?api_key=YOUR_API_KEY&page=0&page_size=100"
```

The response is `{ "lead_enrichment": {…}, "enriched_leads": { "total": 2, "leads": [ … ] } }`. Each lead carries `custom_columns` — the row you submitted, including your `unique_identifier` — plus the enriched contact fields. `total` counts every lead in the job, matched or not.

---

## Key request fields

| Field                          | Required | Description                                                                                                                                                                                                                                                                                                      |
| ------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                         | yes      | Name for the job. Must be unique: a name that's already taken returns `422`, so include something distinctive such as a date or your own ID.                                                                                                                                                                     |
| `source_type`                  | yes      | Always `from_json` for API-submitted jobs.                                                                                                                                                                                                                                                                       |
| `match_field`                  | yes      | How Dealsignal finds each row: `name`, `email`, or `linkedin_url`.                                                                                                                                                                                                                                               |
| `lead_data`                    | yes      | `{ keys: string[], values: string[][] }` — columnar input (see below).                                                                                                                                                                                                                                           |
| `contact_profile_only`         | no       | Enrich the contact profile only — no email or phone enrichment. Don't combine it with the two flags below.                                                                                                                                                                                                       |
| `is_full_prospect_profile`     | no       | Also enrich phone numbers. Without it, `direct_dial` and `contact_profile_only`, the job enriches the contact profile and work email.                                                                                                                                                                            |
| `direct_dial`                  | no       | Also enrich phone numbers, including direct dials. Turns on `is_full_prospect_profile`. The job's `profile_type` shows the resulting tier.                                                                                                                                                                       |
| `append_company_data`          | no       | Add enriched company data alongside contact data.                                                                                                                                                                                                                                                                |
| `contact_refresh_time`         | no       | Freshness threshold in days (1 or more). Contacts verified within this many days before the job are returned without a refresh; older ones are refreshed first. Default 30.                                                                                                                                      |
| `flag_if_lead_changed_company` | no       | Compute `changed_company`: whether the contact's primary employer changed within about the last month before the job (many position dates are only month-precise). It is not a comparison with the values you submit. `false` also covers leads that couldn't be assessed, so it isn't proof the contact stayed. |
| `flag_if_lead_changed_title`   | no       | Same, for the primary title (`changed_title`).                                                                                                                                                                                                                                                                   |
| `webhook`                      | no       | URL to receive a POST when the job completes.                                                                                                                                                                                                                                                                    |

### About `lead_data`

`lead_data` is **columnar**, not row-of-objects: `keys` defines the field names, each entry in `values` is one lead's data in the same order.

```json
{
  "keys":   ["first_name", "last_name", "email", "unique_identifier"],
  "values": [
    ["Jane", "Smith", "jane@acme.example",  "1"],
    ["John", "Doe",   "john@globex.example", "2"]
  ]
}
```

Allowed keys: `first_name`, `last_name`, `company_name`, `email`, `linkedin_url`, `title`, `city`, `state`, `country`, `unique_identifier`.

---

## Webhooks

Provide a `webhook` URL on job creation and Dealsignal will POST a notification when the job finishes. The body is the job object — the same fields as `lead_enrichment` in `GET /api/v1/lead_enrichments/{id}`, without the wrapper. It does not carry the leads; fetch them from `final_result`.

> **Note**
>
> The notification is sent once, while the job is being finalized, so its payload shows `status: "Completion Running"` and `is_completed: false` — treat the webhook's arrival as the completion signal. Acknowledge with any 2xx first, then fetch results; if `final_result` returns a `message` instead of `enriched_leads`, retry after a few seconds. If the job reads `is_completed: true` and `final_result` still returns a `message`, stop retrying and check `page` / `page_size`. If your endpoint was unavailable, poll `GET /api/v1/lead_enrichments/{id}` instead.

---

## Endpoint reference

| Endpoint                                                                                                        | Method | Purpose                     |
| --------------------------------------------------------------------------------------------------------------- | ------ | --------------------------- |
| [`/api/v1/lead_enrichments`](/api-reference/lead-enrichment/create-lead-enrichment-job)                         | `POST` | Create and launch a job.    |
| [`/api/v1/lead_enrichments`](/api-reference/lead-enrichment/list-lead-enrichment-jobs)                          | `GET`  | List all jobs with stats.   |
| [`/api/v1/lead_enrichments/{id}`](/api-reference/lead-enrichment/get-lead-enrichment-job)                       | `GET`  | Single-job status.          |
| [`/api/v1/lead_enrichments/{id}/final_result`](/api-reference/lead-enrichment/get-lead-enrichment-final-result) | `GET`  | Paginated enriched results. |