# Contact Data Validation API - Email, Phone, Address, Lead (`nabeelbaghoor/contact-data-validation-api`) Actor

Validate and enrich contact data through eighteen services on one key: score a whole lead and cross-check its parts, verify email deliverability, look up phone line type carrier and the name on it, parse and validate names, and standardise addresses in the US and worldwide. Pay per result.

- **URL**: https://apify.com/nabeelbaghoor/contact-data-validation-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Business, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 83.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$15.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Contact Data Validation API - Email, Phone, Address, Lead

Eighteen validation and enrichment services behind one key, over one records list. Score a lead, verify an address, look up the name on a phone line, or standardise a hundred thousand addresses. One flat row per record.

### What this actor does

- **Scores a lead and cross-checks its parts.** Most validation tools judge the email, the phone and the address in isolation and hand you three verdicts. This one also checks them against each other, so a real phone number registered three states away from the address on the form comes back as a problem rather than as three passes. Every component score is lifted onto the row alongside the overall score, because the disagreement is usually the finding.
- **Runs eighteen services from one list.** Every mode reads the same records list and takes different fields out of it, so one prepared list of contacts can go through lead scoring, then email validation, then address standardisation, without being rewritten between passes.
- **Verifies email deliverability and repairs typos.** Returns the deliverability verdict with separate flags for catch-all domains, disposable providers, role accounts, spam traps, expired domains and vulgar addresses, plus the corrected address when the input was an obvious misspelling.
- **Looks up who is on a phone line.** Line type, carrier, city, state and time zone, and at full depth the name and address of the contact the number belongs to. Two append modes work the other way, finding the number from a person at an address or from a business.
- **Standardises addresses in the United States and worldwide.** Delivery point validation, residential and business classification, carrier route, county, congressional district and the parsed fragments of the address. The international service covers the rest of the world in the local format.
- **Recovers an address from partial details.** The detective modes take what a form actually collected - a street and a name, a wrong city, a postal code that does not match - and work out the real address rather than failing the record.
- **Geocodes forwards and backwards.** Turn an address into coordinates and place data, or coordinates into the places around them, with a search radius you control.
- **Parses and judges names.** Splits a name into title, first, middle, last and suffix, returns a gender, and flags bogus entries, vulgar entries and celebrity names, which are what a public form collects when it is being tested or abused.
- **Tells three kinds of failure apart.** This provider reports every failure inside a normal response body, so the status line says nothing. A rejected key stops the run because it will never fix itself, a rejected record is written as a miss and the run continues, and a service level failure fails over to the backup host the provider publishes for exactly that case.
- **Distinguishes a wrong key from an unlicensed service.** Each service is licensed separately here, so a perfectly valid key can be refused by a service that is not on your plan. That is a subscription question, not a typo, and the actor says which one it is.
- **Never charges for a miss.** Only rows carrying a resolved result are billed.

### Input

| Field | What it does |
| --- | --- |
| `mode` | Which of the eighteen services to call. |
| `records` | The records to validate, one JSON object per line. |
| `emails` | Shorthand for the email mode: addresses one per line. |
| `phones` | Shorthand for the phone mode: numbers one per line. |
| `names` | Shorthand for the name mode: names one per line. |
| `addresses` | Shorthand for single-line address and geocode modes. |
| `testType` | Judge leads as business or consumer, with or without an address. |
| `phoneTestType` | How deep the phone lookup goes. |
| `nameOption` | The option string passed to the name service. |
| `allowEmailCorrections` | Repair an obvious email typo before validating. |
| `emailTimeoutMs` | Milliseconds the email service may spend on the mail server. |
| `maxMatchesPerRecord` | How many geocoding results one record may return. |
| `searchType` | Search type passed to the geocoding modes. |
| `minCertainty` | Keep only leads at or above this score. |
| `leadQualities` | Keep only leads with these quality ratings. |
| `requireDeliverableEmail` | Drop rows whose email component is unusable. |
| `requireValidPhone` | Drop rows whose phone component is unusable. |
| `requireValidAddress` | Drop rows whose address component is unusable. |
| `environment` | Production, with failover, or the trial host. |
| `requestsPerMinute` | Pace the run under your plan's rate limit. |
| `skipNotFound` | Leave misses and rejected records out of the dataset. |
| `maxResults` | Hard cap on rows, and therefore on spend and run time. |
| `apiKey` | Your own license key. Stored as a secret. |

### Example output

```json
{
  "found": true,
  "mode": "lead-validation",
  "query": "Jane Doe | jane.doe@example.com | 8055551234 | 27 E Cota St, Santa Barbara, CA, 93101",
  "overallCertainty": 87,
  "overallQuality": "Pass",
  "leadType": "Business",
  "leadCountry": "US",
  "noteCodes": "3,7",
  "noteDescription": "Phone is a mobile line, Email domain is a business domain",
  "nameCertainty": 95,
  "nameQuality": "Pass",
  "firstName": "Jane",
  "lastName": "Doe",
  "addressCertainty": 92,
  "addressQuality": "Pass",
  "addressLine1": "27 E COTA ST",
  "addressCity": "SANTA BARBARA",
  "addressState": "CA",
  "addressPostalCode": "93101",
  "addressIsValid": true,
  "emailCertainty": 88,
  "emailQuality": "Pass",
  "emailCorrected": "jane.doe@example.com",
  "emailIsDeliverable": true,
  "phoneCertainty": 76,
  "phoneQuality": "Review",
  "phoneCity": "Santa Barbara",
  "phoneState": "CA",
  "phoneIsValid": true,
  "phoneContactName": "JANE DOE",
  "phoneContactType": "Wireless",
  "businessCertainty": null,
  "error": null,
  "raw": { }
}
```

### Frequently asked questions

#### What does lead validation actually do that separate checks do not?

It cross-references. Validating an email, a phone number and an address separately gives you three independent verdicts, and a fabricated lead can pass all three by combining real components that have nothing to do with each other. This service checks whether the name, address, phone, email and IP address are consistent with one another, and scores both the lead as a whole and each component on a zero to one hundred scale, with note codes explaining what it found. The overall quality is expressed as pass, review or fail, so a form can route the review cases to a human instead of discarding them.

#### How do I decide between the business and consumer test types?

Pick the one the lead is. A business lead is judged against business listings and company data, a consumer lead against consumer records, and a lead judged against the wrong set will score badly for no real reason. The two no-address variants are for forms that never collected an address at all, and they exist so that a missing field does not drag the overall score down as though it were a wrong field.

#### What does the phone lookup return?

At basic depth, the line type and the carrier. At business depth, business listing data attached to the number. At full depth, the contact behind the line: name, address, city, state and whether the line is wireless, landline or VoIP. That last one is the difference between knowing a number is dialable and knowing who picks it up. Deeper lookups spend more of your provider credits, so the depth is a run setting rather than a fixed choice.

#### What is address detective for?

For the records a plain validator gives up on. Real forms collect a street with no city, a city with the wrong postal code, or a name and a phone number with a half-typed address. The detective modes take those partial details and work out the real address, and the outlying variant handles the case where the city or postal code supplied is simply wrong rather than missing. Running validation first and the detective on the failures is usually cheaper than losing the records.

#### What is the difference between a wrong key and an unlicensed service?

Each service here is licensed separately, so your key can be entirely valid and still be refused by a service you have not subscribed to. Those two failures look nearly identical in the raw response, and confusing them sends you hunting for a typo that does not exist. The actor reports them separately: one says the key was rejected, the other says the key was accepted but the service is not on your plan.

#### Why does the actor need to know about a backup host?

Because this provider publishes one, and it is the documented answer to a service level failure rather than an exotic fallback. Failures here arrive with a normal HTTP status and an error object in the body, and one of the error types means the service itself is in trouble. On that error the actor retries the request against the backup host instead of failing the record, which is what keeps a long run alive through a brief outage. This applies to the production environment; a trial key runs against the trial host, which has no backup.

#### Can I run the same list through several modes?

Yes, and that is what the shared records list is for. Every mode reads the same objects and simply takes different fields out of them, so a list carrying names, emails, phones and addresses can be scored as leads, then validated for email, then standardised for address, without being reshaped in between. Each run is a separate run and is billed separately.

#### Which fields does a record need?

Only the ones the mode uses. Lead scoring makes use of everything you give it and scores what is missing as unknown rather than failing. Email validation needs `email`, phone lookup needs `phone`, name validation needs `fullName`, city and postal code validation needs `postalCode`, and reverse geocoding needs `latitude` and `longitude`; records missing the field their mode requires are dropped before the request rather than sent and charged for. Everything else is optional and improves the answer.

#### Do I need my own API key?

Yes. This actor does not include data access. You use your own license key from Service Objects, which is the provider whose contact validation API this actor calls, obtained from their site. Your own plan, credit balance and terms apply. Paste the key into the `apiKey` field, where it is stored as an Apify secret. Set `environment` to trial if your key was issued for the trial host, since a key issued for one host does not work on the other.

#### What happens when a record returns nothing?

An undeliverable address or a failing lead is a verdict, not a miss: the provider telling you the record is bad is the question you asked, so that row is written and billed like any other. A miss is a record the provider returned no result for at all, and a rejection is a record it refused as malformed. Both are written with `found: false` and never billed, and the rejection carries the provider's own explanation. Set `skipNotFound` to true to leave them out of the dataset entirely.

#### How much does a run cost?

Pricing is pay per result: you are charged for each record resolved into the dataset, and never for misses, for rejected records, for rows dropped by the filters, or for duplicates. Note that the geocoding modes can return several matches for one record and each match is a row. Apify platform usage is included in the per-result price. Your own API provider's credit balance is separate and billed by them.

### Keyword map

contact validation API, lead validation API, lead scoring API, email validation API, email verification, phone validation API, phone append, reverse phone lookup, caller name lookup, line type detection, address validation API, US address validation, international address validation, address standardisation, delivery point validation, DPV, residential delivery indicator, address parsing, address autocomplete alternative, city state zip validation, secondary unit numbers, geocoding API, reverse geocoding, name validation API, name parsing, bogus name detection, form validation, lead form fraud, data quality API, data cleansing, CRM data hygiene

# Actor input Schema

## `mode` (type: `string`):

Which service to call. Every mode reads the same records list and simply takes different fields out of it, so one prepared list can be run through several modes without being rewritten.

## `records` (type: `array`):

The records to validate, one JSON object per line. Supply whichever fields the mode needs and leave the rest out. Recognised fields: fullName, firstName, lastName, salutation, gender, dateOfBirth, email, phone, phone2, phone3, ipAddress, businessName, businessDomain, businessEin, address1 to address8, singleLine, city, state, postalCode, country, latitude, longitude, searchRadius, boundaries, extras, outputLanguage, captureTime, testType, label. Identical records are removed so you are never charged twice for the same lookup.

## `emails` (type: `array`):

Shorthand for the email validation mode: addresses one per line, so a simple run does not have to be written as JSON. Added to whatever the records list already holds.

## `phones` (type: `array`):

Shorthand for the phone lookup mode: numbers one per line. Added to whatever the records list already holds.

## `names` (type: `array`):

Shorthand for the name validation mode: names one per line. Added to whatever the records list already holds.

## `addresses` (type: `array`):

Shorthand for the single-line address validation and geocode modes: one whole address per line. The single-line address mode needs the city and state, or the postal code, on the same line, and the provider rejects the record rather than guessing when they are missing. Added to whatever the records list already holds.

## `testType` (type: `string`):

Whether a lead is scored as a business or as a consumer, and whether an address is expected at all. The no-address variants are for forms that never collected one, and they stop a missing address from dragging the overall score down.

## `phoneTestType` (type: `string`):

How far the phone lookup goes. Basic returns line type and carrier, business adds business listing data, and full adds the contact behind the line. Deeper lookups cost more of your provider credits.

## `nameOption` (type: `string`):

The option string passed to the name service. Leave as Default unless the provider has told you to use another value for your account.

## `allowEmailCorrections` (type: `boolean`):

Let the email service repair an obvious typo before validating, and return what it corrected. On by default: a signup that misspelled a common webmail domain by one character is a real subscriber, not a bounce.

## `emailTimeoutMs` (type: `integer`):

How long the email service may spend contacting the receiving mail server. A short timeout finishes faster and returns more inconclusive answers.

## `maxMatchesPerRecord` (type: `integer`):

How many results the geocoding modes may return for one record. Each returned match is a row, so this multiplies both the dataset and the spend.

## `searchType` (type: `string`):

The search type passed to the geocoding modes. Leave as Default unless the provider has told you to use another value.

## `minCertainty` (type: `integer`):

In the lead modes, only keep leads scoring at least this on the provider's zero to one hundred scale. Leave at zero to keep every lead. Applied after the provider answers, so it reduces dataset noise and Apify spend rather than provider credits.

## `leadQualities` (type: `array`):

In the lead modes, only keep leads the provider rated this way, such as Pass, Review or Fail. Leave empty to keep every rating.

## `requireDeliverableEmail` (type: `boolean`):

Drop rows whose email component scored below the provider's usable threshold. Useful when the point of the run is a mailable list rather than a full audit.

## `requireValidPhone` (type: `boolean`):

Drop rows whose phone component scored below the provider's usable threshold, or which the phone service could not confirm.

## `requireValidAddress` (type: `boolean`):

Drop rows whose address component scored below the provider's usable threshold, or which resolved to no address at all.

## `environment` (type: `string`):

Production runs against the provider's live hosts and fails over to their backup host if the primary reports a service failure. Trial runs against the trial host, which is the one a free trial key is issued for. A key issued for one will not work on the other.

## `requestsPerMinute` (type: `integer`):

Pace the run so it stays under whatever rate your plan allows. Lower this if the provider starts refusing requests; raise it to finish a long list sooner.

## `skipNotFound` (type: `boolean`):

Leave records the provider returned nothing for, and records it rejected as malformed, out of the dataset. Off by default, because a rejected record is usually worth seeing. Misses are never charged for either way.

## `maxResults` (type: `integer`):

Stop after this many rows. This is the cap on both spend and run time.

## `apiKey` (type: `string`):

Your own license key for the contact validation API. Note that each service is licensed separately, so a key can be valid and still be refused by a service that is not on your plan; the actor reports those two cases differently. Stored as a secret.

## Actor input object example

```json
{
  "mode": "lead-validation",
  "records": [
    "{\"fullName\":\"Jane Doe\",\"email\":\"jane.doe@example.com\",\"phone\":\"8055551234\",\"address1\":\"27 E Cota St\",\"city\":\"Santa Barbara\",\"state\":\"CA\",\"postalCode\":\"93101\",\"country\":\"US\"}"
  ],
  "testType": "business",
  "phoneTestType": "full",
  "nameOption": "Default",
  "allowEmailCorrections": true,
  "emailTimeoutMs": 5000,
  "maxMatchesPerRecord": 5,
  "searchType": "Default",
  "minCertainty": 0,
  "requireDeliverableEmail": false,
  "requireValidPhone": false,
  "requireValidAddress": false,
  "environment": "production",
  "requestsPerMinute": 300,
  "skipNotFound": false,
  "maxResults": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One row per record, carrying the lead score and its component scores, the email verdict and correction, the phone line and the contact on it, the parsed name, or the standardised address and its coordinates.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "records": [
        "{\"fullName\":\"Jane Doe\",\"email\":\"jane.doe@example.com\",\"phone\":\"8055551234\",\"address1\":\"27 E Cota St\",\"city\":\"Santa Barbara\",\"state\":\"CA\",\"postalCode\":\"93101\",\"country\":\"US\"}"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/contact-data-validation-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "records": ["{\"fullName\":\"Jane Doe\",\"email\":\"jane.doe@example.com\",\"phone\":\"8055551234\",\"address1\":\"27 E Cota St\",\"city\":\"Santa Barbara\",\"state\":\"CA\",\"postalCode\":\"93101\",\"country\":\"US\"}"] }

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/contact-data-validation-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "records": [
    "{\\"fullName\\":\\"Jane Doe\\",\\"email\\":\\"jane.doe@example.com\\",\\"phone\\":\\"8055551234\\",\\"address1\\":\\"27 E Cota St\\",\\"city\\":\\"Santa Barbara\\",\\"state\\":\\"CA\\",\\"postalCode\\":\\"93101\\",\\"country\\":\\"US\\"}"
  ]
}' |
apify call nabeelbaghoor/contact-data-validation-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/contact-data-validation-api"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1zzZQJKVskKvaof3w/builds/K44TUJ8R5YLbdxuFo/openapi.json
