# Contact Verification API - Email, Phone and Address (`nabeelbaghoor/contact-verification-api`) Actor

Verify a whole contact record in one call: the email address, the phone number and the postal address, each with its own verdict and detail code. Get the corrected and standardised postal address back, plus line type and county. Real time or bulk lists. Pay per result.

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

## Pricing

$12.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 Verification API - Email, Phone and Address

Check a whole contact record at once rather than three separate services. Send the email address, the phone number and the postal address together, get a verdict on each, and get the postal address back standardised and corrected. One flat row per contact.

### What this actor does

- **Verifies three things in one call.** Email, phone and postal address are sent as a single contact record and each comes back with its own verdict and its own detail code. That distinction is the point: a lead with a good address and a dead phone is a different problem from one with a good phone and a mistyped street, and a single overall verdict hides which it is.
- **Returns the corrected postal address.** The provider standardises and corrects the address it was given, and returns the corrected form plus the county. A street written as "4010 Boy Scout Boulevard, Suite 1100" comes back in the postal service's own spelling with the full plus four postcode. A `addressCorrected` flag says whether it had to change anything.
- **Gives the detail behind the verdict.** Eleven documented detail codes sit under a non-valid email verdict, separating a mailbox that does not exist from a mailbox that is full, a disposable provider from a role address, and a temporary error that will pass on a retry from a permanent block. All eleven are offered as a filter.
- **Runs real time or bulk, whichever fits.** Real time verifies one contact per request and answers immediately, which suits a few hundred records. Bulk creates a list on the provider's side, polls its own reported state and walks its own reported page count, which suits tens of thousands. Neither state nor page count is guessed at, so a list that finishes faster or slower than expected still exports correctly.
- **Handles both kinds of API key.** This provider issues server side and client side keys, and each answers on its own path; the wrong pairing is rejected without a useful explanation. The actor defaults to the server side path and exposes the other as an option, and says so in the error message when a key is refused.
- **Pairs your three lists line by line.** Emails, phones and postal addresses are matched by position into one contact each, so line three of one list belongs to the same person as line three of the others. Any one list on its own is a valid run.
- **Counts an invalid contact as a result, not a miss.** The provider answers HTTP 200 with a status of invalid, which is exactly the question being asked. Only a record with no verdict at all is a miss, and misses are never billed.

### Input

| Field | What it does |
| --- | --- |
| `mode` | Real time, or bulk lists. |
| `emails` | Email addresses to verify. |
| `phones` | Phone numbers, paired line by line with the emails. |
| `postalAddresses` | Postal addresses, paired line by line with the rest. |
| `keyType` | Whether your key was generated server side or client side. |
| `emailStatuses` | Keep only these email verdicts. |
| `phoneStatuses` | Keep only these phone verdicts. |
| `addressStatuses` | Keep only these address verdicts. |
| `statusDetails` | Keep only these email detail codes. |
| `excludeRoleAddresses` | Drop shared inboxes such as info and support. |
| `excludeDisposable` | Drop throwaway addresses. |
| `requireAllValid` | Keep only contacts where every submitted part is valid. |
| `listSize` | Contacts per bulk list. |
| `requestsPerMinute` | Pace the run under your plan's rate limit. |
| `skipNotFound` | Leave contacts with no verdict out of the dataset. |
| `maxResults` | Hard cap on rows, and therefore on spend and run time. |
| `apiKey` | Your own API key. Stored as a secret. |

### Example output

```json
{
  "found": true,
  "mode": "verify",
  "query": "jane.doe@example.com | 18009618205 | 4010 Boy Scout Boulevard, Suite 1100, Tampa, FL, 33607",
  "contactId": "row_1",
  "email": "jane.doe@example.com",
  "emailStatus": "valid",
  "emailStatusDetail": null,
  "emailAccount": "jane.doe",
  "emailDomain": "example.com",
  "emailConnected": null,
  "phone": "18009618205",
  "phoneStatus": "valid",
  "phoneServiceType": "land",
  "phoneLocation": null,
  "address1": "4010 W Boy Scout Blvd Ste 1100",
  "address2": " ",
  "city": "Tampa",
  "state": "FL",
  "zip": "33607-5796",
  "county": "Hillsborough",
  "addressStatus": "valid",
  "addressCorrected": true,
  "durationSeconds": 0.392828819,
  "error": null,
  "raw": { }
}
```

### Frequently asked questions

#### What does verifying a whole contact record mean?

It means one request carries the email address, the phone number and the postal address for the same person, and the answer carries a verdict for each. You get back whether the mailbox exists, whether the number is a real reachable line and what kind of line it is, and whether the postal address is deliverable, along with the corrected form of that address. Verifying the three separately with three services gives you the same facts but no way to see the record as a whole, which is what you actually act on.

#### What is the difference between the verdict and the detail code?

The verdict is one of valid, invalid, accept all, risky or unknown. The detail code is what sits underneath a verdict that is not valid, and it is where the decisions live. An invalid email can mean the format is wrong, the domain does not exist, or the domain is fine and the specific mailbox is not, and those call for three different follow ups. A risky verdict can mean a full mailbox, a disposable provider, a role address or a server that returned an uncertain answer. Filtering on the detail code is how you retry the recoverable ones and drop the rest.

#### Does it correct a postal address, or just judge it?

It corrects it. The provider returns the address standardised to the postal service's own formatting, with the full postcode and the county added, and a flag saying whether anything had to change. That is the practical reason to run an address check rather than a syntax check: a form entry that a human would read as correct is very often not the form the postal service will route on, and the corrected version is the one to store.

#### Real time or bulk, which should I use?

Real time for anything up to a few hundred contacts, or whenever you want the answer during the run. It verifies one record per request and returns the corrected address. Bulk for tens of thousands: it creates a list on the provider's side, and the run then spends most of its time waiting rather than requesting. Bulk trades immediacy for throughput, and the actor polls the provider's own reported progress rather than a fixed schedule, so a list that finishes early is exported early.

#### My API key is being rejected. Why?

Almost always because of the key type. This provider issues two kinds of key, one meant for browser code and one meant for server code, and each answers only on its own path. A server side key sent to the client side path is refused, and so is the reverse, with a message that does not say which mistake was made. Set the key type field to match the key you generated on the provider's dashboard. An actor is server side, so that is the default here.

#### Can I verify only phone numbers, or only addresses?

Yes. The three input lists are paired by position into one contact record each, and any list you leave empty is simply not part of the record. A run with only phone numbers verifies only phones. The actor also leaves the unused fields out of the request rather than sending empty strings, which matters because asking the provider to verify an empty value is a request you would still be charged for.

#### What counts as a miss, and what gets charged?

An invalid contact is a result, not a miss: the provider answering that a mailbox does not exist is exactly the question you asked, so that row is written and billed like any other. A miss is a record the provider returned no verdict for at all, and those are written with `found: false` and never billed. Rows dropped by your filters and duplicate rows are not billed either.

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

Yes. This actor does not include data access. You use your own API key from BriteVerify, which is the provider whose contact verification API this actor calls, created on their dashboard. Your own plan, credit balance and terms apply. Paste the key into the `apiKey` field, where it is stored as an Apify secret. The key travels in a request header rather than on the URL.

#### How does this handle rate limits and spent credits?

Requests are spaced evenly across the minute so a long list does not bunch up against the limiter, and the pace is yours to set. A rate limit or server error is retried with backoff, because it clears on its own. An empty credit balance is treated differently: the provider reports it with its own status code, the actor recognises it and stops with what it has rather than burning retries on a balance that waiting will not refill.

#### How much does a run cost?

Pricing is pay per result: you are charged for each contact record resolved into the dataset, and never for records with no verdict, for rows dropped by the filters, or for duplicates. 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 verification API, email verification API, phone validation API, address validation API, postal address standardisation, CASS address correction, real time verification, bulk verification, list cleaning, lead form validation, checkout address validation, role address detection, disposable email detection, mailbox full detection, catch-all detection, landline versus mobile, line type lookup, county append, data quality, CRM hygiene

# Actor input Schema

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

Real time verifies one contact per request and answers immediately, which suits a few hundred records and is the only route that returns a corrected postal address. Bulk creates a list on the provider's side, waits for it to finish and exports the results, which suits tens of thousands and spends most of its time waiting rather than requesting.

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

Email addresses, one per line. Paired line by line with the phone numbers and postal addresses below into one contact record each, so line three of this list belongs to the same person as line three of the others. Leave empty to verify only phones or only addresses. An address pasted inside a longer string is extracted before the request.

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

Phone numbers, one per line, paired line by line with the addresses above. Brackets, dots and spaces are stripped before the request, so a pasted list in mixed formats still works. Leave empty to skip phone verification.

## `postalAddresses` (type: `array`):

One postal address per line, paired line by line with the lists above, written as street, city, state, postcode. Both the four part and the three part spelling are understood, so 1 Main St, Boston, MA 02116 works as well as 1 Main St, Boston, MA, 02116. Leave empty to skip address verification.

## `keyType` (type: `string`):

This provider issues two kinds of key, and each answers on its own path. A key made for server use is the normal choice for an actor. Pick client side only if the key you have was generated as a browser key, otherwise the provider will reject it without explaining why.

## `emailStatuses` (type: `array`):

Only keep contacts whose email verdict is one of these. Restricting to valid is how you turn a raw list into one that is safe to send to. Leave empty to keep every verdict. Applied after the provider answers, so it reduces dataset noise and Apify spend rather than provider credits.

## `phoneStatuses` (type: `array`):

Only keep contacts whose phone verdict is one of these. Leave empty to keep every verdict.

## `addressStatuses` (type: `array`):

Only keep contacts whose postal address verdict is one of these. Leave empty to keep every verdict.

## `statusDetails` (type: `array`):

Only keep contacts whose email detail code is one of these. The detail code is what sits under a non-valid verdict, and it is what separates a temporary error that will pass on a retry from a mailbox that genuinely does not exist. Leave empty to keep every detail code.

## `excludeRoleAddresses` (type: `boolean`):

Leave out shared inboxes such as info, sales and support, keeping only addresses that belong to an individual. Useful when the list is meant for one to one outreach.

## `excludeDisposable` (type: `boolean`):

Leave out addresses on throwaway providers, which are created to expire and are worth nothing in a list.

## `requireAllValid` (type: `boolean`):

Only keep contacts where every part you actually submitted came back valid. A record with no phone number is not failed for its phone, so this stays usable when you are verifying only one or two of the three.

## `listSize` (type: `integer`):

How many contacts to put in one bulk list. Larger lists mean fewer jobs to wait on, at the cost of a longer wait for each. Bulk only.

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

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

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

Leave contacts the provider returned no verdict at all for out of the dataset. Note that an invalid contact is a verdict, not a miss, so this does not drop invalid records. Off by default, because keeping the misses is what lets you see which contacts resolved and which did not. 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 API key for the contact verification API. Sent as a request header, never on the URL. Required for every lookup. Stored as a secret.

## Actor input object example

```json
{
  "mode": "realtime",
  "emails": [
    "jane.doe@example.com"
  ],
  "keyType": "serverSide",
  "emailStatuses": [],
  "phoneStatuses": [],
  "addressStatuses": [],
  "statusDetails": [],
  "excludeRoleAddresses": false,
  "excludeDisposable": false,
  "requireAllValid": false,
  "listSize": 10000,
  "requestsPerMinute": 300,
  "skipNotFound": false,
  "maxResults": 100
}
```

# Actor output Schema

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

One row per contact record, with a separate verdict and detail code for the email address, the phone number and the postal address, plus the corrected address.

# 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 = {
    "emails": [
        "jane.doe@example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/contact-verification-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 = { "emails": ["jane.doe@example.com"] }

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/contact-verification-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 '{
  "emails": [
    "jane.doe@example.com"
  ]
}' |
apify call nabeelbaghoor/contact-verification-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/contact-verification-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/SneHkarFVMPHL5J5e/builds/oO2x0jSfg6EAXm9S7/openapi.json
