# Phone Validator, Carrier & TCPA Litigator Lookup (US, Canada) (`checkthatphone/phone-validator`) Actor

Live carrier lookup for US & Canada numbers, $10 per 1,000. Not an offline format check: the carrier a number uses today, line type, deliverability, ported status, plus TCPA litigator scrub, free state-DNC check and landline-SMS routing. No API key to bring, no start fee.

- **URL**: https://apify.com/checkthatphone/phone-validator.md
- **Developed by:** [CheckThatPhone](https://apify.com/checkthatphone) (community)
- **Categories:** Lead generation, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 912 total users, 116 monthly users, 100.0% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $8.00 / 1,000 phone credits

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Validator, Carrier & TCPA Litigator Lookup — US & Canada

Bulk-verify **US & Canada** phone numbers with **real, live carrier data** — not offline format checks. Paste a list of numbers and get back validity, line type, current carrier, deliverability, ported status, geolocation, and optional TCPA litigator scrub, landline-SMS routing, and free state-DNC and DNC-complainer checks. Optionally add an IP to any number for **IP↔phone geolocation matching**, included with the lookup.

**$10 per 1,000 live carrier lookups** on the free plan, down to $8 per 1,000 at the Business tier. No start fee, no API key to bring, no subscription.

Built for lead validation, CRM hygiene, fraud screening, SMS/voice campaign prep, and TCPA compliance.

⚡ Backed by a validation network that has served **1B+ requests**.

### Why this actor

Most phone actors only run an offline format check (Google's `libphonenumber`) — which **returns blank carrier for US/Canada**, because numbers get ported between carriers and the offline data never sees it. This actor hits **live carrier databases**, so you get the *current* carrier (portability-aware), real line type, and deliverability that offline tools can't provide.

- ✅ **Real US/CA carrier & line type** (mobile / landline / VoIP) — current, not carrier-at-issuance
- ✅ **Deliverability** — flags numbers a carrier deactivated recently (up to 45 days), plus ported and undeliverable numbers
- 📍 **Built-in geo-IP** — add an IP and get IP↔phone geo match (country, state, city, metro, timezone), included with every lookup (not a separate add-on)
- 🛡️ **TCPA litigator scrub** — flag known TCPA litigators & serial plaintiffs from industry-leading data
- 📵 **State DNC & complainers checks** — free: state do-not-call registries (38 states plus DC) and a national complainer list, each reporting whether it ran
- 📩 **Landline-SMS lookup** — detect text-enabled landlines and their messaging provider
- 🔁 **Auto-dedup** — one lookup per unique number (or phone+IP pair)
- 📦 **Bulk-native** — one run handles a handful or hundreds of thousands of numbers

### Geo-IP enrichment 📍

Add an IP after any number — `phone,ip` — and the result includes the IP validation (`ipResult`) plus full IP-derived geolocation (`geoCountry`, `geoState`, `geoCity`, `geoMetro`, `timezone`, `tzOffset`, with `geoSource: ip`). It works for **IPv4 and IPv6**, and it's **included with the base lookup** — not a separate add-on. Perfect for **fraud screening** — compare where the phone is registered against where the IP resolves to catch mismatches at signup.

### TCPA litigator scrub 🛡️

Turn on **litigator scrub** and every number is checked against a daily-refreshed database of **known TCPA litigators and serial plaintiffs** — the professional filers who seed their numbers into lead lists and turn a single call or text into a **$500–$1,500** statutory claim (and a class action from there). Flagged rows come back with `litigator`, `litigator_type`, and `litigator_name`, so you can suppress them *before* you dial or send — while keeping every clean number you can legitimately contact.

This isn't some bolted-on freebie: we screen against **industry-leading litigation data** — the same caliber the largest TCPA-compliance platforms rely on — built from **federal and state court records and demand-letter activity, refreshed daily**. At one extra credit per number, it's protection that costs a rounding error next to a single claim.

Pair it with line type + deliverability for a complete pre-send pass: drop litigators, skip deactivated/undeliverable numbers, and route landlines correctly — in one run.

### State DNC & complainers checks 📵

Two separate checks, both on by default and **free — they never add a credit**. The **state DNC check** screens each number against state do-not-call registries (38 states plus DC, refreshed weekly). The **complainers check** screens it against a national list of roughly **700,000 people who have lodged complaints against telemarketers** but haven't sent a demand letter or filed suit. Each check reports whether it ran (`dncStateChecked`, `dncComplainerChecked`) and its match (`dncStateResult`, `dncComplainerResult`).

The honest part: 12 states (Colorado, Florida, Indiana, Louisiana, Massachusetts, Mississippi, Missouri, Oklahoma, Pennsylvania, Tennessee, Texas, and Wyoming) only distribute their registries to directly registered organizations, so they aren't in the data. Numbers there come back with `dncStateChecked: "false"` — "not checked", never "clear". The **federal** DNC registry is not included — scrub it separately.

### Pricing & plan limits 💳

Billed per **credit**, never per run — there is **no start fee**. One number = 1 credit, **+1** if the TCPA litigator scrub is on (every number is screened), **+1** if landline-SMS is on *and* the number is a landline (mobiles are never surcharged). The state-DNC and complainers checks are **free**. So a number costs **1–3 credits**, and you're billed the exact per-row credits the lookup returns — never an estimate.

Your unit price drops with your Apify subscription tier:

| | **Free** | **Starter / Scale / Business** |
|---|---|---|
| Price per 1,000 credits | $10.00 | $9.50 / $9.00 / $8.00 |
| Credits per month | 500 | Unlimited |
| Concurrent runs | 1 at a time | Unlimited |
| Numbers per run | Capped by your Apify prepaid balance (~$5/mo on the free plan) | Capped only by the max cost per run you set |
| Live carrier data | Full | Full |
| Add-ons (litigator, DNC, landline-SMS, geo-IP) | All included | All included |
| Output fields | Identical | Identical |
| Start / subscription fee | None | None |

A free account is a **full-featured trial** — same live carrier data, same add-ons, same output. Only the three caps differ, and none of them fail your run:

- **500 credits/month**, resetting on the 1st (UTC). A run that would exceed the cap finishes *successfully* with a notice explaining the limit — you are not charged for skipped work.
- **One run at a time.** Start a second while the first is still going and it exits with a notice, not an error. Wait for the first to finish.
- **Prepaid balance.** When your Apify spending limit can't cover the whole list, the actor trims the run to what fits and logs exactly how many numbers it processed and how many credits remain.

### Input

- **Phone numbers** — one per line, any format (E.164, national, dashes, parentheses). Most lines are just a number; the IP is optional. To also geo-locate a row, append `,ip` to that line only (`phone,ip`) — without it, geolocation falls back to the number's area code. Duplicates are removed automatically.
- **TCPA litigator scrub** — flag professional plaintiffs / serial litigators.
- **Landline SMS lookup** — detect text-enabled landlines: messaging provider, country, and whether the landline can receive texts. Off by default (adds 1 credit per landline; mobiles are never surcharged) — turn it on when you plan to text landlines.
- **State DNC & complainers checks** — free; state do-not-call registry and complainer-list results, each with a per-number "did it run" flag.

```json
{
  "phoneNumbers": [
    "6108095225",
    "(704) 712-2446",
    "515-494-5996",
    "+1 212-987-6543",
    "6473351234, 99.240.60.100",
    "4157012311, 71.76.83.173"
  ],
  "litigatorFilter": true,
  "landlineSmsLookup": false,
  "dncState": true,
  "dncComplainer": true
}
```

### Output

One row per number written to the run's dataset (export as JSON, CSV, or Excel). Fields use the same native names as the [CheckThatPhone API docs](https://checkthatphone.com/docs), so single-call and bulk results are identical.

| Field | Description |
|---|---|
| `subscriber` | The number looked up |
| `action` | `send` / `unsubscribe` / `error` — the contact verdict |
| `deliverable` | Whether it's safe/possible to contact |
| `reason` | Explanation when not deliverable (e.g. deactivated) |
| `deactivationDate` | When the carrier deactivated it, if applicable |
| `nanpType` | `mobile` / `landline` / `not-mobile` |
| `dipCarrier` | Current carrier (portability-aware) |
| `dipCarrierType` / `dipCarrierSubType` | e.g. `mobile` / `PCS`, `landline` / `RBOC` |
| `dipPorted` / `dipLrn` / `dipOcn` | Portability + routing details |
| `blackList` | Known-bad flag |
| `litigatorLookup` | Whether the litigator scrub ran for this number (`true`/`false` — reflects the **TCPA litigator scrub** toggle) |
| `litigator` / `litigator_type` / `litigator_name` | TCPA litigator scrub result — flag, classification, and source list (add-on) |
| `dipMessagingLookup` | Whether the landline-SMS lookup ran for this number (`true`/`false` — reflects the **Landline SMS lookup** toggle) |
| `dipMessagingEnabled` / `dipMessagingProvider` / `dipMessagingCountryCode` | Landline-SMS routing (add-on) |
| `dncStateChecked` / `dncComplainerChecked` | Whether that check ran for this number (`true`/`false`, or `error` when it couldn't complete — treat as unavailable, not clear). The state check reads `false` in the 12 uncovered states. |
| `dncStateResult` / `dncComplainerResult` | `STATE DNC` / `DNC COMPLAINER` on a match; empty otherwise. Only meaningful when the matching `*Checked` field is `true`. |
| `dncOtherChecked` | Legacy: `true` when either check ran. Use the per-check fields above. |
| `dncStateCovered` | Deprecated: same answer as `dncStateChecked`. Kept for existing integrations. |
| `smsEligible` / `doNotSms` | SMS-eligibility flags (present only when `true`, inverses of each other): can receive SMS vs. should not be texted (undeliverable or a known TCPA litigator) |
| **`ipResult`** | IP validation (`valid-v4` / `valid-v6`) — when an IP is supplied |
| **`geoCountry` / `geoState` / `geoCity` / `geoMetro`** | Geolocation (IP-derived when an IP is supplied, else area-code) |
| `geoSource` | `ip` or `area-code` |
| `timezone` / `tzOffset` | IANA timezone + UTC offset |

### Disclaimer

The litigator and do-not-call signals are **informational screening data, not legal advice**. A flag (or its absence) is not a determination that contacting a number is lawful, and it does not guarantee compliance with the TCPA, federal or state do-not-call rules, or any other law. Data is refreshed on the schedules described above and can be incomplete. You remain responsible for your own outbound compliance — consent records, internal opt-outs, the federal Do-Not-Call registry, registries in states not covered by our data, and legal review where appropriate.

### Notes

- **Coverage:** United States & Canada (NANP). Non-NANP numbers are skipped.
- **Scale:** one run handles up to ~1M numbers; large lists may take a while — the run polls to completion on its own.
- **Dedup:** the same number with two different IPs is two distinct lookups (each is a separate geo check); the same number+IP twice is one.
- **Billing:** see [Pricing & plan limits](#pricing-and-plan-limits) above — 1–3 credits per number depending on which paid add-ons engage, billed on the exact per-row credits returned.

# Actor input Schema

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

US & Canada phone numbers to verify, one per line. Any format works (E.164, national, dashes, parentheses). Most lines are just a phone number. Optionally, to also get IP↔phone geolocation (ipResult + country/state/city/metro/timezone — included with the lookup, not a separate add-on), append an IP after a comma on that line only: `phone,ip` (IPv4 or IPv6) — see the last two prefilled lines. The IP is optional and per-line; leave it off and geolocation falls back to the number's area code. Duplicates are removed automatically (one lookup per unique number, or phone+IP pair). Billed per credit, not per result — one number can be 1–3 credits: litigator scrub adds +1 per number, landline-SMS adds +1 only on landlines (mobiles aren't surcharged). Free Apify accounts are limited by their Apify prepaid balance (~$5/mo of platform credit); paid plans have no balance limit.

## `litigatorFilter` (type: `boolean`):

Adds 1 credit per number — every number is screened. Flag known TCPA serial plaintiffs / professional litigators. Screened against industry-leading litigation data — the same caliber the largest TCPA-compliance platforms rely on — built from federal & state court records and demand-letter activity, refreshed daily.

## `landlineSmsLookup` (type: `boolean`):

Detect text-enabled landlines (SMS-to-landline routing): messaging provider, country, and whether the landline can receive texts. Off by default — it adds 1 credit per landline (mobiles are never surcharged), so turn it on when you plan to text landlines.

## `dncState` (type: `boolean`):

Free — adds no cost. Screens each number against state do-not-call registries (38 states plus DC, refreshed weekly) and returns dncStateChecked and dncStateResult. The 12 states that only distribute their registries to directly registered organizations are skipped: CO, FL, IN, LA, MA, MS, MO, OK, PA, TN, TX, WY. For those, dncStateChecked is "false" — not checked, never clear. The federal DNC registry is not included — scrub it separately.

## `dncComplainer` (type: `boolean`):

Free — adds no cost. Screens each number against a national list of roughly 700,000 people who have lodged complaints against telemarketers but have not sent a demand letter or filed suit. Returns dncComplainerChecked and dncComplainerResult. Informational: a match never changes action.

## `dncOther` (type: `boolean`):

Deprecated — use dncState and dncComplainer. When set, it turns both checks on or off, so saved tasks and integrations that still send it keep working.

## Actor input object example

```json
{
  "phoneNumbers": [
    "6108095225",
    "(704) 712-2446",
    "515-494-5996",
    "+1 212-987-6543",
    "8005550199",
    "6473351234, 99.240.60.100",
    "4157012311, 71.76.83.173",
    "2126647665, 172.56.29.234"
  ],
  "litigatorFilter": true,
  "landlineSmsLookup": false,
  "dncState": true,
  "dncComplainer": true
}
```

# Actor output Schema

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

One row per number: line type, current carrier, deliverability, geo-IP, litigator scrub, DNC scrub, landline-SMS, and credits used.

# 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": [
        "6108095225",
        "(704) 712-2446",
        "515-494-5996",
        "+1 212-987-6543",
        "8005550199",
        "6473351234, 99.240.60.100",
        "4157012311, 71.76.83.173",
        "2126647665, 172.56.29.234"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("checkthatphone/phone-validator").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": [
        "6108095225",
        "(704) 712-2446",
        "515-494-5996",
        "+1 212-987-6543",
        "8005550199",
        "6473351234, 99.240.60.100",
        "4157012311, 71.76.83.173",
        "2126647665, 172.56.29.234",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("checkthatphone/phone-validator").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 '{
  "phoneNumbers": [
    "6108095225",
    "(704) 712-2446",
    "515-494-5996",
    "+1 212-987-6543",
    "8005550199",
    "6473351234, 99.240.60.100",
    "4157012311, 71.76.83.173",
    "2126647665, 172.56.29.234"
  ]
}' |
apify call checkthatphone/phone-validator --silent --output-dataset

```

## MCP server setup

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

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/XfLU0iePKsTkKQZsY/builds/tbPiqJpjCyeePuIpP/openapi.json
