# Phone Number Enrichment & Validator — Bulk Reverse Lookup (`memo23/phone-enrichment`) Actor

Bulk phone validator + US reverse lookup in one actor. Every number: valid/invalid, E.164, country, region, carrier, line type — 100% offline. Opt-in US enrichment adds the owner: name, age, emails, other phones, addresses, relatives. Pay per match, misses free. JSON/CSV/API.

- **URL**: https://apify.com/memo23/phone-enrichment.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Lead generation, AI, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 number validateds

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/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Phone Number Enrichment & Validator — Bulk Reverse Lookup

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/phone-enrichment-logo.png" alt="Phone Enrichment logo" width="220" />
</p>

Two tools in one actor. Feed it a **list** of phone numbers and it validates every one **100% offline** — valid/invalid, E.164, country, region, carrier, line type — no login, no network, no ban risk. Then, for US numbers, flip on **owner enrichment** and each number is reverse-looked-up into the **person behind it**: name, age, emails, other phone numbers, current and past addresses (with coordinates), relatives and associates. Bulk, not one-number-at-a-time. **You pay per matched owner — misses are free.**

| Input | Row emitted |
| --- | --- |
| Any phone number (E.164 or local + default country) | One validated row — E.164, country, region, carrier, line type |
| A valid **US** number, with `enrichOwner` on | The same row **plus an `owner` object** — name, age, emails, addresses, relatives |

> 100% offline validation. The optional US owner lookup runs through the actor's own residential unblocker — no API key, no account, no per-lookup cost to you.

### Why Use This Actor?

- **Validate the whole list for almost nothing.** Offline libphonenumber validation is deterministic and network-free, so you can clean tens of thousands of numbers per run at ~$1 / 1,000 — no rate limits, no proxies, no risk.
- **Then turn US numbers into people.** Owner enrichment resolves a US number to a full person record: `fullName`, `age`, `emails[]`, `otherPhones[]`, `currentAddress` (with lat/long), `pastAddresses[]`, `relatives[]`, `associates[]`.
- **Bulk — not one number per run.** Other reverse-lookup actors make you launch a separate run for every single number. This one takes a whole list and processes it in parallel.
- **Pay per match, misses are free.** The owner-enrichment charge fires **only** when a real person is resolved. A number that doesn't come back costs you nothing — so a cold or wrong list never runs up a bill.
- **No keys, no accounts.** Both the offline validator and the US reverse lookup run inside the actor. Nothing to sign up for.
- **Clean, consistent rows.** Every field that doesn't resolve comes back `null`/empty rather than missing, so your CSV/JSON schema is stable for import.

### Overview

The actor runs in two stages, and the second is opt-in:

- **Validate (always, offline).** Every number is parsed with Google's libphonenumber metadata (bundled) — is it a real, assigned number for its country, what line type (mobile / fixed / VoIP / toll-free), which region and carrier, and its canonical E.164 form. This never touches the network.
- **Enrich US owner (opt-in).** When `enrichOwner` is on, each **valid US** 10-digit number is reverse-looked-up to the person behind it. Non-US numbers are validated and passed through untouched; US numbers that don't resolve are emitted (unless you filter them out) but never charged.

A realistic note on coverage: US reverse lookup resolves numbers that appear in public people-search records — strong for landlines and long-held mobile numbers, thinner for brand-new or heavily-private numbers. Because misses are free, an unresolved number never costs you anything.

### Supported Inputs

- **`phoneNumbers`** — an array of numbers, one per entry. E.164 (`+15558675309`) is best; local numbers work with `defaultCountry`.
- **`phoneNumbersText`** — paste a whole column (newline / comma / semicolon separated). Merged and de-duplicated with the array.
- **`defaultCountry`** — ISO country (e.g. `US`) used to parse numbers that don't start with `+`.

### Use Cases

| Who | What they use it for |
| --- | --- |
| **Lead-gen & sales** | Clean a raw phone list, then enrich US numbers into named contacts with emails and addresses for outreach. |
| **Skip tracing / collections** | Resolve a US number to the current person, their other numbers, and current + past addresses. |
| **Fraud & identity checks** | Confirm a number is a real, assigned line of the expected type, and see who it's associated with. |
| **CRM hygiene** | Bulk-validate stored numbers (drop invalid/garbage), attach carrier + line type, and hydrate US records. |
| **Data teams** | One actor for validation + enrichment instead of stitching a validator and a reverse-lookup API together. |

### How It Works

![How Phone Enrichment works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-phone-enrichment.png)

1. **Input** — an array, a pasted column, or a CSV of numbers in any format (punctuation is stripped). Thousands per run.
2. **Validate (offline)** — each number → valid/invalid, E.164, country + calling code, line type, region and carrier, computed entirely from bundled metadata.
3. **Enrich US owner (opt-in)** — each valid US number is reverse-looked-up to the person: name, age, emails, other phones, current + past addresses with coordinates, relatives and associates.
4. **Export** — one flat row per number, streamed to the dataset: JSON, CSV, Excel, or the Apify API.

### Input Configuration

| Field | Type | Description |
| --- | --- | --- |
| `phoneNumbers` | array | Numbers to validate / enrich, one per entry. E.164 preferred; local works with `defaultCountry`. |
| `phoneNumbersText` | string | Paste a column of numbers (newline / comma / semicolon separated). Merged + de-duplicated. |
| `defaultCountry` | string | ISO 3166-1 alpha-2 (e.g. `US`, `GB`) for numbers without a leading `+`. |
| `includeGeoCarrier` | boolean | Attach region + carrier (offline). Default `true`. |
| `onlyValid` | boolean | Emit only valid, assigned numbers — drops garbage/typos. Default `false`. |
| `enrichOwner` | boolean | Turn on US reverse-phone owner enrichment. Billed per match; misses free. Default `false`. |
| `onlyMatched` | boolean | With enrichment on, emit only rows that resolved to a person. Default `false`. |
| `enrichConcurrency` | integer | Parallel owner lookups (1–15). Default `5`. |
| `maxItems` | integer | Hard cap on numbers processed this run. |
| `proxy` | object | Optional override; leave empty to use the built-in residential unblocker. |

#### Example input

```json
{
  "phoneNumbers": ["+12128675309", "+14155552671", "(512) 555-0143"],
  "defaultCountry": "US",
  "includeGeoCarrier": true,
  "enrichOwner": true,
  "onlyMatched": false
}
````

### Output Overview

One flat JSON object per number. Validation fields are always present; the `owner` object and `ownerMatched` flag appear only when `enrichOwner` is on. Download as JSON, CSV, Excel, or via the Apify API.

### Output Samples

Validation only (`enrichOwner` off):

```jsonc
{
  "input": "+1 212-867-5309",
  "valid": true,
  "possible": true,
  "e164": "+12128675309",
  "international": "+1 212 867 5309",
  "national": "(212) 867-5309",
  "countryCode": "US",
  "countryCallingCode": "+1",
  "lineType": "FIXED_LINE_OR_MOBILE",
  "region": "New York, NY",
  "carrier": null,
  "error": null,
  "processedAt": "2026-07-23T18:20:00.000Z"
}
```

A valid US number enriched to its owner (`enrichOwner: true`) — illustrative shape:

```jsonc
{
  "input": "+15125550143",
  "valid": true,
  "e164": "+15125550143",
  "countryCode": "US",
  "lineType": "FIXED_LINE_OR_MOBILE",
  "region": "Austin, TX",
  "ownerMatched": true,
  "owner": {
    "fullName": "Jordan Rivera",
    "age": 44,
    "emails": ["jordan.rivera@example.com"],
    "otherPhones": ["(512) 555-0199"],
    "currentAddress": {
      "streetAddress": "123 Congress Ave", "addressLocality": "Austin",
      "addressRegion": "TX", "postalCode": "78701",
      "latitude": 30.2672, "longitude": -97.7431
    },
    "pastAddresses": [
      { "streetAddress": "456 Old Rd", "addressLocality": "Dallas", "addressRegion": "TX", "postalCode": "75201", "latitude": null, "longitude": null }
    ],
    "relatives": [{ "name": "Alex Rivera", "profileUrl": "https://www.truepeoplesearch.com/find/person/…" }],
    "associates": [{ "name": "Sam Doe", "profileUrl": "https://www.truepeoplesearch.com/find/person/…" }],
    "profileUrl": "https://www.truepeoplesearch.com/find/person/…",
    "source": "truepeoplesearch"
  },
  "processedAt": "2026-07-23T18:20:01.000Z"
}
```

A valid US number that didn't resolve — emitted (unless `onlyMatched`), and **not charged** for enrichment:

```jsonc
{
  "input": "+12125550100",
  "valid": true,
  "e164": "+12125550100",
  "countryCode": "US",
  "ownerMatched": false,
  "owner": null,
  "processedAt": "2026-07-23T18:20:02.000Z"
}
```

### Key Output Fields

**Validation (always)**

- `valid` / `possible` — assigned number / well-formed for its country
- `e164` · `international` · `national` — canonical formats
- `countryCode` · `countryCallingCode` · `lineType` · `region` · `carrier`

**Owner enrichment (`enrichOwner` on)**

- `ownerMatched` — whether a person was resolved (the billing gate)
- `owner.fullName` · `owner.age` · `owner.emails[]` · `owner.otherPhones[]`
- `owner.currentAddress` (with `latitude`/`longitude`) · `owner.pastAddresses[]`
- `owner.relatives[]` · `owner.associates[]` · `owner.profileUrl` · `owner.source`

### Pricing

Pay-per-event — charged for results, not runtime:

| Event | When it fires | Rate |
| --- | --- | --- |
| Number validated | One number emitted to the dataset (validity, E.164, country, carrier, line type — offline). | $0.001 |
| US owner matched | The opt-in reverse lookup resolves a US number to a real person. **Never fires on a miss.** | $0.02 |
| Actor start | Once per run. | Free |

A 1,000-number list with owner enrichment on and 300 US matches: 1,000 × $0.001 + 300 × $0.02 = **$7.00**, and every unresolved number is free. Validation-only runs are just $0.001/number.

### What makes this different

| Capability | One-per-run reverse lookups | Validation-only actors | This actor |
| --- | --- | --- | --- |
| Bulk (many numbers per run) | ✗ (one per run) | ✓ | ✓ |
| Offline validation (E.164, carrier, line type) | ✗ | ✓ | ✓ |
| US owner: name, age, emails, other phones | partial | ✗ | ✓ |
| Current **+ past** addresses with coordinates | ✗ | ✗ | ✓ |
| Relatives + associates | ✗ | ✗ | ✓ |
| Pay only on a match (misses free) | sometimes | n/a | ✓ |

### Notes & limitations

- **Owner enrichment is US-only.** Non-US numbers are validated and passed through; enrichment is skipped for them (never charged).
- **Validation is offline and definitive; enrichment depends on public records.** A valid US number that isn't in public people-search data returns `ownerMatched: false` — and isn't billed.
- **Not a live-carrier HLR ping.** Line type and carrier come from libphonenumber metadata (the number's assigned range), not a real-time network query — so there's no cost, rate limit, or ban risk.
- **Enrichment throughput** is bounded by `enrichConcurrency` (default 5) since it's network-bound; validation alone runs much faster.

### 🤖 For AI Agents & LLM Apps

**Purpose:** bulk phone validation (offline) + opt-in US reverse-phone owner enrichment, in one actor.

**Minimal tested input:**

```json
{ "phoneNumbers": ["+12128675309"], "enrichOwner": true }
```

**Output fields (flat, per number):** always `input, valid, possible, e164, international, national, countryCode, countryCallingCode, lineType, region, carrier`. With `enrichOwner`: `ownerMatched` (boolean) and `owner` (object with `fullName, age, emails[], otherPhones[], currentAddress{…,latitude,longitude}, pastAddresses[], relatives[], associates[], profileUrl, source`) — `owner` is `null` on a miss.

**Billing:** `number-validated` $0.001 per emitted row; `owner-matched` $0.02 fires ONLY when `ownerMatched` is true (US match); actor-start free. Enrichment misses are never billed.

**Agent-relevant behaviors:** set `onlyValid: true` to drop garbage, `onlyMatched: true` to keep only enriched US contacts; enrichment is US-only and skipped for other countries; results stream to the default dataset; input accepts a pasted blob via `phoneNumbersText`; no API keys required.

### FAQ

**Do I need an API key or account?** No. Offline validation and the US reverse lookup both run inside the actor.

**Is validation a live network check?** No — it's 100% offline (Google's libphonenumber). That's why it has no rate limit, no cost per number beyond the tiny event fee, and can't get anything banned. It answers "is this a real, assigned number and what kind of line," not "is the handset switched on right now."

**Am I charged for numbers that don't resolve to a person?** No. The `owner-matched` charge fires only when a real person comes back. Misses — and all non-US numbers — are free of the enrichment charge.

**Which countries does owner enrichment cover?** US numbers. Everything else is validated and passed through without enrichment.

**Can I validate without enriching?** Yes — leave `enrichOwner` off (the default) and you get a fast, cheap, offline validation run.

**What formats can I paste?** Anything — `+1 (212) 867-5309`, `212.867.5309`, `+12128675309`. Punctuation is stripped; set `defaultCountry` for numbers without a country code.

**What export formats are supported?** JSON, CSV, Excel, XML, JSONL, or the Apify API — plus Make, Zapier, n8n, webhooks and scheduling.

### Support

- **Found a bug or need a field?** Open a ticket on the **Issues** tab — fastest way to reach me and I actively maintain this actor.
- **Email:** <muhamed.didovic@gmail.com>
- **Website:** [muhamed-didovic.github.io](https://muhamed-didovic.github.io/)

### Additional Services

- International owner enrichment beyond the US (via a provider key)
- Custom fields, filters, or export formats for your workflow
- Private or dedicated actors for high-volume or compliance-sensitive use

Reach out via the Issues tab or email.

### Explore More Scrapers

Browse my other Apify actors on my profile: [memo23 on Apify](https://apify.com/memo23).

### ⚠️ Disclaimer

This actor validates phone numbers offline and, for US numbers, retrieves **publicly available** people-search information — the same data any visitor can look up on public reverse-phone directories. It does not access private data, bypass authentication, or scrape gated content.

You are responsible for how you use the data you collect. Reverse-lookup and contact data is regulated: use it in compliance with applicable laws (including the FCRA, GDPR, TCPA, CAN-SPAM, CCPA and other privacy, consumer-reporting, and anti-spam regulations) and any contractual obligations. **This data may not be used for FCRA-covered purposes** such as eligibility for credit, employment, insurance, or housing. Finding a person's contact information does not constitute consent to contact them — ensure your outreach complies with the relevant laws in your jurisdiction. Do not use this tool to facilitate spam, harassment, stalking, or any violation of privacy.

### SEO Keywords

phone number validator, bulk phone validation, phone enrichment, reverse phone lookup, phone number lookup, reverse phone number, us reverse phone lookup, caller id lookup, skip tracing, skip trace, phone to name, phone owner lookup, e164 validator, carrier lookup, line type lookup, mobile or landline, phone number verification, bulk phone checker, phone number cleaner, crm phone hygiene, lead enrichment, contact enrichment, people search api, find person by phone, phone osint, phone number osint, validate phone numbers bulk, phone data enrichment, neuralverge alternative

# Actor input Schema

## `phoneNumbers` (type: `array`):

Phone numbers to validate and (optionally) enrich — one per entry. E.164 format like +15558675309 is best; local numbers like (555) 867-5309 work when you also set a Default country. Any punctuation (spaces, dashes, parentheses, a leading +) is fine — it's stripped automatically.

## `phoneNumbersText` (type: `string`):

Alternative to the field above — paste a whole column of numbers separated by new lines, commas, or semicolons. Merged and de-duplicated with the Phone numbers list.

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

ISO 3166-1 alpha-2 country code (e.g. US, GB, DE) used to parse numbers that DON'T start with a + and country code. Leave empty if every number is already in +E.164 form.

## `includeGeoCarrier` (type: `boolean`):

Attach the geographic region (e.g. "California") and mobile carrier / network operator (e.g. "Verizon") for each number, derived 100% offline from Google's libphonenumber metadata. Turn off for a slightly faster run.

## `onlyValid` (type: `boolean`):

Emit only rows that parse to a valid, assigned number for their country — drops garbage / typo / unassigned input so your export is clean.

## `enrichOwner` (type: `boolean`):

Opt-in reverse lookup for US numbers. When on, each valid US 10-digit number is resolved to the person behind it — full name, age, emails, other phone numbers, current + past addresses (with coordinates when available), relatives and associates. Non-US numbers and numbers that don't resolve are skipped. Billed per matched owner only — misses are FREE. Adds an `owner` object and an `ownerMatched` flag to each row.

## `onlyMatched` (type: `boolean`):

When owner enrichment is on, emit only the numbers that resolved to a person — so your dataset is pure enriched contacts. Has no effect unless "Enrich US owner" is on.

## `enrichConcurrency` (type: `integer`):

How many US owner lookups to run in parallel. Higher is faster but heavier on the reverse-lookup source; 5 is a safe default. Only matters when "Enrich US owner" is on.

## `maxItems` (type: `integer`):

Hard cap on how many numbers to process this run.

## `proxy` (type: `object`):

Leave empty — owner lookups already route through the actor's own residential unblocker at no extra cost to you. Only set this to force your own proxies on the initial fetch attempt.

## Actor input object example

```json
{
  "phoneNumbers": [
    "+12128675309",
    "+14155552671"
  ],
  "includeGeoCarrier": true,
  "onlyValid": false,
  "enrichOwner": false,
  "onlyMatched": false,
  "enrichConcurrency": 5,
  "maxItems": 100000
}
```

# 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 = {
    "phoneNumbers": [
        "+12128675309",
        "+14155552671"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/phone-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 = { "phoneNumbers": [
        "+12128675309",
        "+14155552671",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/phone-enrichment").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "phoneNumbers": [
    "+12128675309",
    "+14155552671"
  ]
}' |
apify call memo23/phone-enrichment --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/phone-enrichment",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Phone Number Enrichment & Validator — Bulk Reverse Lookup",
        "description": "Bulk phone validator + US reverse lookup in one actor. Every number: valid/invalid, E.164, country, region, carrier, line type — 100% offline. Opt-in US enrichment adds the owner: name, age, emails, other phones, addresses, relatives. Pay per match, misses free. JSON/CSV/API.",
        "version": "0.0",
        "x-build-id": "47afDYmL3jJDhFTjF"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~phone-enrichment/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-phone-enrichment",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~phone-enrichment/runs": {
            "post": {
                "operationId": "runs-sync-memo23-phone-enrichment",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~phone-enrichment/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-phone-enrichment",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "phoneNumbers": {
                        "title": "Phone numbers",
                        "type": "array",
                        "description": "Phone numbers to validate and (optionally) enrich — one per entry. E.164 format like +15558675309 is best; local numbers like (555) 867-5309 work when you also set a Default country. Any punctuation (spaces, dashes, parentheses, a leading +) is fine — it's stripped automatically.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "phoneNumbersText": {
                        "title": "Paste a list of numbers",
                        "type": "string",
                        "description": "Alternative to the field above — paste a whole column of numbers separated by new lines, commas, or semicolons. Merged and de-duplicated with the Phone numbers list."
                    },
                    "defaultCountry": {
                        "title": "Default country (for local numbers)",
                        "type": "string",
                        "description": "ISO 3166-1 alpha-2 country code (e.g. US, GB, DE) used to parse numbers that DON'T start with a + and country code. Leave empty if every number is already in +E.164 form."
                    },
                    "includeGeoCarrier": {
                        "title": "Include region & carrier",
                        "type": "boolean",
                        "description": "Attach the geographic region (e.g. \"California\") and mobile carrier / network operator (e.g. \"Verizon\") for each number, derived 100% offline from Google's libphonenumber metadata. Turn off for a slightly faster run.",
                        "default": true
                    },
                    "onlyValid": {
                        "title": "Only output valid numbers",
                        "type": "boolean",
                        "description": "Emit only rows that parse to a valid, assigned number for their country — drops garbage / typo / unassigned input so your export is clean.",
                        "default": false
                    },
                    "enrichOwner": {
                        "title": "🔎 Enrich US owner (reverse phone → the person)",
                        "type": "boolean",
                        "description": "Opt-in reverse lookup for US numbers. When on, each valid US 10-digit number is resolved to the person behind it — full name, age, emails, other phone numbers, current + past addresses (with coordinates when available), relatives and associates. Non-US numbers and numbers that don't resolve are skipped. Billed per matched owner only — misses are FREE. Adds an `owner` object and an `ownerMatched` flag to each row.",
                        "default": false
                    },
                    "onlyMatched": {
                        "title": "Only output rows with a matched owner",
                        "type": "boolean",
                        "description": "When owner enrichment is on, emit only the numbers that resolved to a person — so your dataset is pure enriched contacts. Has no effect unless \"Enrich US owner\" is on.",
                        "default": false
                    },
                    "enrichConcurrency": {
                        "title": "Enrichment concurrency",
                        "minimum": 1,
                        "maximum": 15,
                        "type": "integer",
                        "description": "How many US owner lookups to run in parallel. Higher is faster but heavier on the reverse-lookup source; 5 is a safe default. Only matters when \"Enrich US owner\" is on.",
                        "default": 5
                    },
                    "maxItems": {
                        "title": "Max numbers",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on how many numbers to process this run.",
                        "default": 100000
                    },
                    "proxy": {
                        "title": "Proxy configuration (optional override)",
                        "type": "object",
                        "description": "Leave empty — owner lookups already route through the actor's own residential unblocker at no extra cost to you. Only set this to force your own proxies on the initial fetch attempt."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
