# Phone Number Lookup & Enrichment — Reverse Phone & Carrier (`logical_vivacity/phone-number-enrichment`) Actor

Turn phone numbers into people. Validates any number worldwide (E.164, carrier, line type, location) and, for US numbers, identifies the owner with name, address and email. Repeat numbers in a run are billed at a fraction. Confidence score on every record.

- **URL**: https://apify.com/logical\_vivacity/phone-number-enrichment.md
- **Developed by:** [Logical Vivacity](https://apify.com/logical_vivacity) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 0 monthly users, 83.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Phone Number Lookup & Enrichment — Reverse Phone, Carrier & Line Type

**A number in any format goes in. A decided record comes out.**

Is it a real number? Is it a mobile you can text, a landline, or a VoIP line? Which carrier? Which country, region and timezone? And — for US numbers — *whose number is it*: name, age, email, city, and whether they still use it.

One record per number, with a 0-100 confidence score so you can tell what is certain from what is merely likely.

***

### Try it in 30 seconds

Paste these into **Phone numbers**, tick the terms box, and hit Start:

```
(425) 281-1646
+1 214-978-7456
+44 20 7946 0958
```

Messy formats are fine — brackets, dots, dashes, spaces, with or without a country code. Numbers without a `+` are read using your **Default country** setting.

***

### What you get per number

```jsonc
{
  "input": "(425) 281-1646",
  "e164": "+14252811646",
  "national": "(425) 281-1646",
  "international": "+1 425-281-1646",
  "countryCode": 1,
  "country": "US",
  "isValid": true,
  "isPossible": true,

  "lineType": "wireless",          // what the source has actually seen, not a numbering-plan guess
  "reportedCarrier": "T-Mobile USA, Inc.",
  "location": "Seattle, WA",
  "timezones": ["America/Los_Angeles"],

  "identityFound": true,           // US numbers only
  "ownerName": "Keil York",
  "ownerAge": 34,
  "ownerEmail": "keilyork@yahoo.com",
  "ownerEmails": ["keilyork@yahoo.com"],
  "ownerAddress": "3418 SW Holden St, Seattle, WA 98126",
  "ownerCity": "Seattle", "ownerState": "WA", "ownerZip": "98126",
  "aliases": ["Keil M York"],
  "lastReportedActive": "Aug 2026",
  "isCurrentForOwner": true,
  "otherNumbersForOwner": ["(206) 555-0148"],

  "confidence": 100,               // 0-100: how much of the number's story we established
  "sourcesUsed": 1,
  "status": "ok",
  "scrapedAt": "2026-09-17T18:04:11Z"
}
```

A non-US number comes back with everything except the person:

```jsonc
{
  "input": "+44 20 7946 0958",
  "e164": "+442079460958",
  "national": "020 7946 0958",
  "country": "GB",
  "isValid": true,
  "lineType": "landline",
  "location": "London",
  "timezones": ["Europe/London"],
  "identityFound": false,
  "confidence": 35,
  "status": "ok"
}
```

Export as JSON, CSV, Excel, XML or HTML, or pull it straight from the API.

***

### Who uses this

**Sales and outbound teams** — clean a call list before you dial. Drop the dead numbers, route the mobiles to SMS, and know which name to open with.

**Fraud, risk and onboarding** — check a number before you approve an account: does it exist, is it a disposable VoIP line, does the name on it match the name on the application?

**Debt recovery and collections** — find the person behind an old account number, see when it was last reported active, and get their other numbers when this one has gone quiet.

**CRM hygiene** — bulk-validate the numbers already in your database, fix the formats to E.164, and flag the ones that are no longer valid.

**Anyone deciding whether to dial** — a landline at 7pm is a wasted call; a mobile is a conversation. Line type is the cheapest routing decision you can make.

***

### What makes it different

**Validation *and* identity in one record.** Most tools do one or the other — a validator that tells you the number is real but not whose it is, or a people-search that needs a clean number to start with. This returns both in one row, so your spreadsheet has one column set, not two exports to join.

**Line type from what has actually been seen.** The numbering plan alone can only say what a range is *allowed* to be — and in the US that is very often "landline or mobile", which helps nobody. Where a public record shows the number in the wild, we return what it has actually been reported as (`wireless`, `landline`, `voip`) and fall back to the numbering plan only when nothing has.

**A confidence score on every row.** 0-100, built from what we could establish: validity, line type, carrier, owner name, address, email, whether the number is current, and whether more than one source agreed. Auto-accept above 90, review the rest.

**Repeats cost a fraction.** Dirty lists are full of duplicates. A number that appears five times in a run is looked up once — the first occurrence is billed at the full rate and the other four at the much cheaper repeat rate.

**Cross-check mode.** Turn on *Cross-check every number against a second source* and we check a second independent source and merge the results, raising confidence where they agree. For high-value lists where a wrong name is expensive.

**Nothing to configure.** No API keys, no accounts, no proxies to set up. Connection handling, retries and pacing are managed for you.

***

### Owner lookup is US only — plainly

Owner identification (`ownerName`, `ownerAge`, `ownerEmail`, addresses, aliases, `otherNumbersForOwner`, relatives, past addresses) works for **US numbers only**.

Every other country still gets the full number picture: formatting, validity, line type, carrier, location and timezones — but `identityFound` will be `false` and the owner fields will be empty. That is a coverage limit, not an error, and those rows are still returned and charged because the validation data stands on its own. If you only want rows with a person on them, turn on **Only return numbers where a person was identified** and unmatched numbers come back as `not_found`, unbilled.

***

### Settings

| Setting | What it does |
|---|---|
| **Phone numbers** | Your numbers, one per line, in any format |
| **Default country** | Which country to assume for numbers typed without a `+` country code. Numbers starting with `+` ignore this |
| **Find the person behind the number** | Adds the owner block. US numbers only. Off = pure validation / carrier run |
| **Only return numbers where a person was identified** | Unmatched numbers come back `not_found` and are not charged |
| **Include relatives and associates** | Adds likely relatives to the owner block |
| **Include past addresses** | Adds the owner's previously reported addresses |
| **Cross-check against a second source** | Higher accuracy and confidence, higher cost |

There are no proxy, concurrency or retry knobs. There is nothing to tune.

***

### Bulk lists and automation

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~phone-number-enrichment/runs?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
        "numbers": ["(425) 281-1646", "+1 214-978-7456", "+44 20 7946 0958"],
        "defaultCountry": "US",
        "findOwner": true,
        "onlyIdentified": false,
        "acceptTerms": true
      }'
```

Works with Make, Zapier, n8n, Google Sheets and the Apify API, and as an MCP tool for AI agents. Schedule it to re-check a call list on any cadence.

***

### Results you can trust

Every input reports what happened, so nothing fails silently:

| `status` | Meaning | Charged? |
|---|---|---|
| `ok` | The number was read and enriched — with or without an owner | Yes (repeats at the repeat rate) |
| `invalid_input` | That text isn't a phone number at all; the message says why | No |
| `invalid_number` | It parses, but it isn't a valid number for its country | No |
| `not_found` | No person could be tied to the number, and you asked for identified numbers only | No |
| `error` | A source was briefly unavailable — retry that number | No |

***

### FAQ

**Which countries return an owner?**
The United States, and only the United States. Every other country returns full validation, line type, carrier, location and timezone data, but no person.

**Why does a perfectly valid number have no owner?**
Usually because no public record ties a name to it: freshly issued numbers, business lines, prepaid and burner numbers, VoIP numbers, and numbers belonging to people with a thin public record often have nobody attached. The number is still real — we just can't say whose it is.

**What is the difference between `lineType` and `reportedCarrier`?**
`lineType` is mobile / landline / VoIP; `reportedCarrier` is the network the number sits on. On US numbers both prefer what a public record has actually reported for that number, and fall back to the numbering plan otherwise.

**Does a mobile line type mean I'm allowed to call or text it?**
No — that is your decision and your legal risk. In the US, calls and texts to mobiles are regulated (TCPA, do-not-call registries, state rules and carrier policies), and this Actor does not check any do-not-call list or consent record. Line type tells you what the line *is*, not what you may lawfully do with it. Scrub against your own DNC and consent data before dialling.

**Do duplicates cost full price?**
No. A number repeated in the same run is looked up once; the first occurrence is billed at the full rate and each repeat at a much lower repeat rate. Duplicate rows are marked `fromCache`.

**Can I pull every number in an area code?**
No. This Actor answers lookups about numbers you supply. It is not a bulk database export.

**How fresh is it?**
Read live at the moment of your run. `lastReportedActive` tells you when the number was last reported in use, and `scrapedAt` records exactly when we looked.

***

### Terms of Use

By running this Actor (ticking **I accept the Terms of Use**) you agree to the following.

**1. Permitted use.** You may use the results only for a lawful purpose that you have determined is permitted in your jurisdiction — for example verifying a contact detail, preventing fraud, recovering a debt, cleaning a customer database, or contacting a person in connection with a legitimate business, legal or investigative purpose.

**2. FCRA — prohibited uses.** This Actor is **not** a consumer reporting agency and its output is **not** a consumer report under the US Fair Credit Reporting Act. You may **not** use the results, in whole or in part, to make decisions about consumer credit, insurance, employment, tenant or housing screening, government benefits, or any other purpose regulated by the FCRA or a comparable law.

**3. Other prohibited uses.** You may not use the results to stalk, harass, threaten, dox, intimidate or discriminate against any person, or for unlawful marketing — including calls, texts or automated dialling that violate the TCPA, do-not-call rules, consent requirements or similar laws. Line type is informational and is not permission to contact anyone.

**4. Your responsibility as data controller.** You are solely responsible for how you collect, store, use, share and delete the results, and for complying with all applicable privacy, data-protection, marketing and consumer-protection laws in your jurisdiction, including responding to any opt-out, access or deletion request you receive from a data subject.

**5. No warranty of accuracy.** Records are aggregated from third-party public sources and may be incomplete, outdated or wrong. Confidence scores are estimates, not guarantees of identity, and a number may have changed hands since it was last reported. Verify independently before you act on a result, especially before contacting anyone or taking a decision that affects them.

**6. No relationship with carriers or sources.** This Actor is not affiliated with, endorsed by, or sponsored by any telecommunications carrier, numbering authority, or third-party data source or brand. Carrier names are returned as reported and are used only to identify the network.

**7. Liability.** The Actor is provided "as is", without warranties of any kind. To the maximum extent permitted by law, the developer is not liable for any loss or damage arising from your use of the results, and you agree to indemnify the developer against claims arising from your use.

**8. Removal requests.** If you are an individual and want your information removed, contact the underlying public-records sources directly; records are not stored by this Actor after your run completes.

If you do not agree to these terms, do not run this Actor.

***

*A number it couldn't crack, or need volume pricing?* Open an issue on the Actor's Issues tab.

# Actor input Schema

## `numbers` (type: `array`):

One number per line, in any format — with or without a country code, with brackets, spaces, dots or dashes. Numbers repeated in the same run are looked up once and billed at the cheaper repeat rate.

## `defaultCountry` (type: `string`):

Used only for numbers typed WITHOUT a leading + and country code — they are read as belonging to this country. Numbers that start with + are always read as written, whatever this is set to.

## `findOwner` (type: `boolean`):

Adds owner name, age, email addresses, address, aliases, when the number was last reported active and the owner's other numbers. Owner identification is available for US numbers ONLY. Non-US numbers still come back fully validated with country, line type, carrier, location and timezones — but without a person. Turn this off for a pure validation / carrier run.

## `onlyIdentified` (type: `boolean`):

When on, numbers with no identity come back as `not_found` and are NOT charged. When off (the default), those numbers are still returned — and charged — with their validation, line type, carrier, location and timezone data, which is useful on its own.

## `includeRelatives` (type: `boolean`):

Adds the names of likely relatives and associates of the owner. US numbers only.

## `includePastAddresses` (type: `boolean`):

Adds the owner's previously reported addresses. US numbers only.

## `crossVerify` (type: `boolean`):

Slower and costs more, but checks a second independent source and merges the two results, raising the confidence score where they agree. Worth it for high-value lists and dispute-sensitive work.

## `acceptTerms` (type: `boolean`):

Required. I confirm I have a lawful purpose for this data and that I will NOT use it for credit, insurance, employment, tenant screening or any other FCRA-regulated decision, nor for stalking or harassment. I am the data controller for the results and am responsible for how they are used, including honoring opt-out and deletion requests, and for complying with calling and texting rules such as the TCPA and do-not-call lists.

## Actor input object example

```json
{
  "numbers": [
    "(425) 281-1646",
    "+1 214-978-7456",
    "+44 20 7946 0958"
  ],
  "defaultCountry": "US",
  "findOwner": true,
  "onlyIdentified": false,
  "includeRelatives": false,
  "includePastAddresses": false,
  "crossVerify": false,
  "acceptTerms": true
}
```

# Actor output Schema

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

Every number with its validation, carrier, line type and owner details.

## `overview` (type: `string`):

The same rows as a spreadsheet-style table, with the most useful columns first.

# 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 = {
    "numbers": [
        "(425) 281-1646",
        "+1 214-978-7456",
        "+44 20 7946 0958"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("logical_vivacity/phone-number-enrichment").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 = { "numbers": [
        "(425) 281-1646",
        "+1 214-978-7456",
        "+44 20 7946 0958",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("logical_vivacity/phone-number-enrichment").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 '{
  "numbers": [
    "(425) 281-1646",
    "+1 214-978-7456",
    "+44 20 7946 0958"
  ]
}' |
apify call logical_vivacity/phone-number-enrichment --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,logical_vivacity/phone-number-enrichment"
        }
    }
}
```

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/FledlCSOhzzY6GOkD/builds/u0Q1I5o5OcHObqpOz/openapi.json
