# Bulk Phone Number Validator & Formatter (`bite-sized-insights/validator-phone`) Actor

Validate phone numbers in bulk. Get E.164, international, national and RFC 3966 formats, validity and length checks, country, number type, carrier, location and time zones for each number. Set a default region for local formats.

- **URL**: https://apify.com/bite-sized-insights/validator-phone.md
- **Developed by:** [bite-sized-insights](https://apify.com/bite-sized-insights) (community)
- **Categories:** Developer tools, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 apify-default-dataset-items

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

***Validate phone numbers in bulk - normalize to E.164, international and national formats, check validity and
possibility, detect the country and number type, and get carrier, location and time zones where available.***

Provide a list of phone numbers in any common written format and get back a structured record for each one: the
clean E.164 form, whether it is possible and valid for its country, which country it belongs to, whether it is a
mobile, fixed line, VoIP, toll-free or other number type, plus carrier, geographic description and time zones.

No login required. No cookies needed. Pay-per-event pricing.

### Why Choose This Actor?

**"Clean your phone list before you dial, text or import it"**

Our Bulk Phone Number Validator provides:

- **Four Output Formats**: E.164, international, national and `tel:` URI, ready for CRMs, dialers and SMS tools
- **Two Independent Checks**: a length-based possibility check and a stricter validity check against the numbering
  plan of the number's country
- **Country Detection With Region Hints**: numbers with a `+` prefix carry their own country; for local formats set a
  default region for the whole run or a region hint on individual entries
- **Rich Metadata**: number type, carrier, location description and time zones for valid numbers
- **Cost-Effective**: Pay only for the numbers you validate: `$0.80 / 1k numbers`
- **No Third-Party Dependency**: runs entirely on bundled numbering-plan data - no upstream service to fail or
  rate-limit you, and your list never leaves the run

### Quick Start

```json
{
  "phone_numbers": ["+14155552671", "020 7946 0958", "+33 6 12 34 56 78", "12345"],
  "default_region": "GB"
}
```

### Usage Examples

#### Validate Local Numbers With a Default Region

```json
{
  "phone_numbers": ["020 7946 0958", "07911 123456"],
  "default_region": "GB"
}
```

#### Use a Region Hint per Number

```json
{
  "phone_numbers": [
    "+4930901820",
    { "phone_number": "0301234567", "region": "DE" },
    { "phone_number": "(415) 555-2671", "region": "US" }
  ]
}
```

### Output Example

```json
{
  "phone_number": "+33 6 12 34 56 78",
  "e164": "+33612345678",
  "international": "+33 6 12 34 56 78",
  "national": "06 12 34 56 78",
  "rfc3966": "tel:+33-6-12-34-56-78",
  "country_code": 33,
  "region_code": "FR",
  "is_possible": true,
  "possibility": "is_possible",
  "is_valid": true,
  "number_type": "mobile",
  "carrier": "SFR",
  "location": "France",
  "time_zones": ["Europe/Paris"],
  "reason": null
}
```

```json
{
  "phone_number": "020 7946 0958",
  "e164": "+442079460958",
  "international": "+44 20 7946 0958",
  "national": "020 7946 0958",
  "rfc3966": "tel:+44-20-7946-0958",
  "country_code": 44,
  "region_code": "GB",
  "is_possible": true,
  "possibility": "is_possible",
  "is_valid": true,
  "number_type": "fixed_line",
  "carrier": null,
  "location": "London",
  "time_zones": ["Europe/London"],
  "reason": null
}
```

```json
{
  "phone_number": "abc",
  "e164": null,
  "international": null,
  "national": null,
  "rfc3966": null,
  "country_code": null,
  "region_code": null,
  "is_possible": false,
  "possibility": null,
  "is_valid": false,
  "number_type": null,
  "carrier": null,
  "location": null,
  "time_zones": [],
  "reason": "Not a phone number"
}
```

### Input Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `phone_numbers` | array | Yes | 1-100,000 numbers (max 64 characters each); text or `{phone_number, region}` |
| `default_region` | string | No | Two-letter country code (e.g. `US`, `GB`) for numbers written without a `+` prefix |

### Output Fields

| Field | Type | Description |
|-------|------|--------------|
| `phone_number` | string | The phone number exactly as provided in the input |
| `e164` | null/string | Normalized E.164 form, or null if the number could not be parsed |
| `international` | null/string | International display format |
| `national` | null/string | National display format |
| `rfc3966` | null/string | `tel:` URI form |
| `country_code` | null/integer | Country calling code (for example 44) |
| `region_code` | null/string | Two-letter country code, or null if it cannot be determined |
| `is_possible` | boolean | Whether the number has a possible length for its country |
| `possibility` | null/string | Length check result, e.g. `is_possible`, `too_short`, `too_long` |
| `is_valid` | boolean | Whether the number matches a valid numbering plan pattern for its country |
| `number_type` | null/string | Valid numbers only, e.g. `mobile`, `fixed_line`, `voip` (see the FAQ) |
| `carrier` | null/string | Original carrier of the number range, where known |
| `location` | null/string | Geographic description (city, region or country), where known |
| `time_zones` | array | IANA time zones the number may belong to |
| `reason` | null/string | Short explanation when the number could not be parsed or is not valid, otherwise null |

### Pricing

| Cost | Description |
|------|-------------|
| $0.0001 / start | Charged per actor run |
| $1.50 / 1,000 numbers | Charged per phone number validated |

### API Integration

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/bite-sized-insights/validator-phone/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_numbers": ["+14155552671", "020 7946 0958"],
    "default_region": "GB"
  }'
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("bite-sized-insights/validator-phone").call(
    run_input={
        "phone_numbers": ["+14155552671", "020 7946 0958"],
        "default_region": "GB",
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['phone_number']}: valid={item['is_valid']} type={item['number_type']} ({item['reason']})")
```

#### JavaScript

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('bite-sized-insights/validator-phone').call({
    phone_numbers: ['+14155552671', '020 7946 0958'],
    default_region: 'GB',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => {
    console.log(`${item.phone_number}: valid=${item.is_valid} type=${item.number_type} (${item.reason})`);
});
```

### Use Cases

- **CRM and Lead Cleanup**: Normalize imported or purchased contact lists to E.164 and drop numbers that cannot exist
- **SMS and Dialer Preparation**: Keep only valid mobile numbers before a text campaign, and separate fixed lines,
  VoIP and toll-free numbers
- **Signup and Form Checks**: Batch-check numbers collected through forms or trial signups
- **Call Scheduling**: Use the time zones of each number to call at sensible local hours
- **Fraud Signals**: Flag VoIP, premium-rate or country-mismatched numbers as a low-cost first-pass signal

### FAQ

#### Does this tell me if a number is active or can receive calls?

No. The checks confirm that a number is correctly formed and falls within a number range allocated in its country.
They cannot show whether the number is currently assigned to a subscriber, switched on, or reachable, so there is
deliberately no "deliverable" verdict. Use a live carrier lookup or an SMS or call test if you need that.

#### Which number types can be returned?

`number_type` is one of `mobile`, `fixed_line`, `fixed_line_or_mobile`, `toll_free`, `premium_rate`, `shared_cost`,
`voip`, `personal_number`, `pager`, `uan`, `voicemail` or `unknown`. Some countries do not distinguish mobile from
fixed line, which is what `fixed_line_or_mobile` means.

#### What is the difference between possible and valid?

`is_possible` only checks that the length fits the country's numbering plan. `is_valid` additionally checks the
number's prefix and pattern against the country's allocated ranges. A number can be possible but not valid.

#### How accurate are the carrier and location fields?

They describe the range a number was originally allocated from. Numbers that were later ported to another carrier
still show the original one, and many countries (including the United States and Canada) have no carrier data at
all, so `carrier` is often null. `location` is as precise as the country's allocation data allows: a city for many
fixed lines, only the country for most mobile numbers.

#### How are numbers without a country code handled?

A number starting with `+` always uses its own country code. For other numbers, the region hint on the entry is used,
then the `default_region` input. Without either, the number cannot be interpreted and `reason` explains why.

#### Is my phone list stored or shared anywhere?

No. Input is processed for the duration of the run only and results are written to your own private run dataset,
same as any other Apify actor.

### Disclaimer

This actor validates numbers against numbering-plan rules. It does not contact the number, a carrier or any
messaging service, and cannot guarantee that a number is in service. Numbering plans change over time; results
reflect the data bundled with the current version of the actor.

***

**Need help?** Open an issue on the actor's repository or contact support through Apify Console.

# Actor input Schema

## `phone_numbers` (type: `array`):

Phone numbers to validate. An entry is text or {"phone_number", "region"}.

## `default_region` (type: `string`):

Optional two-letter country code (e.g. US, GB, DE) for numbers written without a + prefix.

## Actor input object example

```json
{
  "phone_numbers": [
    "+14155552671",
    "020 7946 0958",
    "+33 6 12 34 56 78",
    "12345"
  ],
  "default_region": "US"
}
```

# Actor output Schema

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

Per-number results: formats, validity, country, type, carrier, location, time zones

# 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 = {
    "phone_numbers": [
        "+14155552671",
        "020 7946 0958",
        "+33 6 12 34 56 78",
        "12345"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bite-sized-insights/validator-phone").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 = { "phone_numbers": [
        "+14155552671",
        "020 7946 0958",
        "+33 6 12 34 56 78",
        "12345",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("bite-sized-insights/validator-phone").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 '{
  "phone_numbers": [
    "+14155552671",
    "020 7946 0958",
    "+33 6 12 34 56 78",
    "12345"
  ]
}' |
apify call bite-sized-insights/validator-phone --silent --output-dataset

```

## MCP server setup

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

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/Mo3u3xKd88u9H74n3/builds/av1Y3jEkHQOi6u9Bb/openapi.json
