# Phone Number Validator & Formatter: E.164, Type, Country (`ataism/phone-validator`) Actor

Offline phone validator: lists or CSV/JSON/XLSX to E.164, country, type, reason. $0.30 per 1,000. Format check only: no carrier, region or time zone lookup.

- **URL**: https://apify.com/ataism/phone-validator.md
- **Developed by:** [Kaizoku Data](https://apify.com/ataism) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.30 / 1,000 phone 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/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 Validator & Formatter: E.164, Type, Country

Check and clean phone numbers **you supply** (a list, or a CSV / JSON / XLSX file): validity, E.164, international and national formats, country, number type (mobile, fixed line, VoIP, toll-free, premium rate, ...) and the reason when a number is invalid. Runs offline with Google's libphonenumber rules (via `libphonenumber-js`): no browser, no proxy, no API key.

**Price: $0.30 per 1,000 numbers ($0.0003 per number).** One row per number, valid or invalid. Blank lines, dropped duplicates and file-error rows are free. No start fee of our own on top of Apify's default.

- **Normalise:** any common format in, E.164 out (`+442079460958`), plus international (`+44 20 7946 0958`), national (`020 7946 0958`) and RFC 3966 (`tel:+442079460958`) forms.
- **Classify:** country (ISO code and name), calling code and number type from the national number plan, including `FIXED_LINE_OR_MOBILE` where the plan cannot tell.
- **Explain:** every invalid number gets a reason code (`TOO_SHORT`, `TOO_LONG`, `INVALID_COUNTRY`, `NOT_A_NUMBER`, `INVALID_NUMBER`, ...): see [Reason codes](#reason-codes).
- **Bulk:** up to 1,000,000 numbers per run, from a typed list or up to 20 files (CSV, TSV, JSON, NDJSON, XLSX; 50 MB each), with optional de-duplication on E.164.
- **Quick start:** press *Start*. The prefilled input validates 12 fictional or reserved numbers (UK, US and Australian ranges set aside for fiction) in about a second for $0.0036.

> **What "valid" means here.** This Actor checks **format and number-plan ranges only**: whether a number has a plausible length and falls inside a range that the country's numbering plan has allocated. It makes **no network lookups**, no carrier or HLR queries and no owner or reverse lookups, so it **cannot tell you whether a line is connected, reachable, ported or who owns it**. A valid number may be disconnected; a number in a recently allocated range may show as invalid until the library's rules are updated.
>
> **What it does not do.** There is **no carrier lookup, no region or city lookup (no geocoding) and no time-zone lookup**. `country` comes from the calling code and the number plan only (for example `GB`, `US`); `type` says mobile, fixed line, VoIP and so on, but never which operator or where. Those need data this Actor does not have.

### Input

| Field | What it does |
|---|---|
| **Phone numbers** | One number per line, any common format. Prefilled with fictional numbers. Blank lines are skipped free, and so is any cell longer than 1,000 characters (see `INPUT_TOO_LARGE`). |
| **File URLs** | Direct `http(s)` links to a CSV/TSV, JSON, NDJSON or XLSX file (up to 20, 50 MB each). Private and local addresses are blocked, as are Google and social-platform links (upload the file instead). A link that returns a web page (a "share" link from Dropbox, OneDrive and similar sites), a PDF or an image is refused as `FILE_NOT_DATA`, free. |
| **Uploaded files** | Upload from your computer to a key-value store (the field offers this) or paste a record URL. |
| **Column name** | Header (CSV, XLSX) or field (JSON objects) with the numbers, case-insensitive; `2` means the second column. Empty is fine for one-column files and JSON arrays of strings. |
| **Sheet name** | XLSX sheet to read; default the first sheet. |
| **Default country** | ISO code (`GB`, `US`, `DE`, ...) for numbers without `+`. Without it, such numbers return `INVALID_COUNTRY`. Numbers with `+` ignore it. Prefilled with `GB`; it is not applied unless you send it. |
| **International / National / RFC 3966** | Switch each formatted field on or off (all on by default). `e164` is always present. |
| **Output invalid numbers** | On (default): invalid numbers get a (charged) row with the reason. Off: they are left out and not charged. |
| **Remove duplicates** | Keep the first row per E.164 number (`020 7946 0958` and `+44 20 7946 0958` match). Dropped duplicates are free. |
| **Max numbers** | Stop after N non-blank numbers. Hard limit 1,000,000 per run (larger values are lowered with a warning). |

#### Example inputs

**1. A pasted list, UK default:**

```json
{
  "phoneNumbers": ["020 7946 0958", "+1 202-555-0143", "07700 900123", "12345"],
  "defaultCountry": "GB"
}
```

**2. A CSV export, de-duplicated, valid numbers only:**

```json
{
  "fileUrls": ["https://example.com/contacts.csv"],
  "column": "Mobile",
  "defaultCountry": "US",
  "dedupe": true,
  "outputInvalid": false
}
```

**3. An XLSX sheet, E.164 only:**

```json
{
  "fileUrls": ["https://example.com/leads.xlsx"],
  "sheetName": "Leads",
  "column": "phone",
  "includeInternational": false,
  "includeNational": false,
  "includeRfc3966": false
}
```

### Output

One dataset row per number, in input order (typed list first, then each file):

```json
{
  "inputIndex": 0,
  "source": "list",
  "input": "+44 20 7946 0958",
  "valid": true,
  "possible": true,
  "e164": "+442079460958",
  "international": "+44 20 7946 0958",
  "national": "020 7946 0958",
  "rfc3966": "tel:+442079460958",
  "country": "GB",
  "countryName": "United Kingdom",
  "callingCode": "44",
  "type": "FIXED_LINE",
  "extension": null,
  "error": null,
  "errorMessage": null
}
```

An invalid number keeps whatever could be parsed:

```json
{
  "inputIndex": 4,
  "source": "list",
  "input": "12345",
  "valid": false,
  "possible": false,
  "e164": "+4412345",
  "country": "GB",
  "type": null,
  "error": "TOO_SHORT",
  "errorMessage": "The number has too few digits for its country."
}
```

- `valid` = inside an allocated number-plan range. `possible` = only the length is plausible (weaker).
- `type` is set for valid numbers: `MOBILE`, `FIXED_LINE`, `FIXED_LINE_OR_MOBILE`, `TOLL_FREE`, `PREMIUM_RATE`, `SHARED_COST`, `VOIP`, `PERSONAL_NUMBER`, `PAGER`, `UAN`, `VOICEMAIL`, or `null` when the plan does not say. Numbers in shared plans (for example +44 mobile prefixes of Guernsey or Jersey) report the territory in `country`.
- For an invalid number, `country` is the default country when one applied, or empty.
- An extension in the input (`ext. 12`) goes to `extension`; `e164` never contains it.
- `warning` and `warningMessage` appear only on a number read from an Excel cell that holds a number rather than text: see [Numbers in Excel files](#numbers-in-excel-files).
- Rows with `valid: null` are free rows (never charged): a file that could not be read, a cell that is too large to be a number, or a row the dataset refused. They carry `error`, `errorMessage` and a `runId` (the id of the run that wrote them).
- `inputIndex` counts non-blank numbers. The run also saves a `RUN_SUMMARY` record: counts of valid and invalid numbers, reasons, duplicates dropped, files read and failed, rows charged and why the run stopped.

#### Reason codes

`error` holds one of these codes whenever a row is not a valid number. The same codes are listed, with an enum, in the dataset schema.

**Number reasons** (the row is charged: you got an answer):

| Code | Meaning |
|---|---|
| `NOT_A_NUMBER` | The text does not look like a phone number. |
| `INVALID_COUNTRY` | No country could be determined: add `+` and the country code, or set a default country. |
| `INVALID_COUNTRY_CODE` | The country calling code after the `+` does not exist. |
| `TOO_SHORT` | The number has too few digits for its country. |
| `TOO_LONG` | The number has too many digits for its country (text over 250 characters always gets this). |
| `INVALID_LENGTH` | The number has a length that does not exist in its country. |
| `INVALID_NUMBER` | The length fits but no number-plan range of the country matches. |

**Free rows** (`valid: null`, never charged; `input` is `null`, so nothing you supplied is echoed back):

| Code | Meaning |
|---|---|
| `INPUT_TOO_LARGE` | A cell longer than 1,000 characters. It cannot be a phone number and is not read. `inputIndex` and `source` tell you where it was. After 1,000 of these the run stops (`stoppedBy: "unpaid-work-cap"`): check the column name. |
| `ROW_REJECTED` | The dataset refused the row (for example because it was too large), so it was left out. |
| `FILE_HTTP` | The server did not answer with HTTP 200. |
| `FILE_BLOCKED` | The address is private, local or otherwise refused (also after a redirect). |
| `FILE_PLATFORM` | A Google, video or social-platform link: upload the file instead. |
| `FILE_TOO_LARGE` | The file is over 50 MB. |
| `FILE_TIMEOUT` | The download timed out or stalled. |
| `FILE_DNS` | The host name could not be resolved. |
| `FILE_NETWORK` | The connection failed. |
| `FILE_REDIRECTS` | More than 5 redirects. |
| `FILE_INVALID_URL` | Not a valid http(s) URL. |
| `FILE_DOWNLOAD` | The file could not be downloaded for another reason. |
| `FILE_NOT_DATA` | The link returned a web page (HTML), a PDF, an image or another file that is not CSV, JSON or XLSX, for example a Google Sheets, Dropbox or OneDrive share link. Use a direct download link, or upload the file. |
| `FILE_COLUMN_NOT_FOUND` | The column or field name was not found in the first row. |
| `FILE_COLUMN_REQUIRED` | The file has several columns (or JSON objects): set "Column name". |
| `FILE_SHEET_NOT_FOUND` | The sheet name was not found in the workbook. |
| `FILE_BAD_FILE` | The file is damaged or could not be read as CSV, JSON or XLSX. |
| `FILE_TOO_LARGE_IN_MEMORY` | A JSON or XLSX file too big for this run's memory: raise the memory or use CSV. |
| `FILE_SKIPPED` | Not read, because five earlier files in the run had already failed. |

If every file fails and there are no typed numbers, the run fails with a message.

#### Numbers in Excel files

Excel stores a number typed into a cell as a number, not as text: it drops a leading zero (`020 7946 0958` typed without a `+` becomes `2079460958`) and keeps only 15 significant digits. The Actor reads the cell's raw value, writes exponent forms such as `4.42079460958E+11` out as plain digits, and restores leading zeros when the cell's number format pads them (a format such as `00000000000`). When it cannot know whether something was lost, the row carries a warning:

| `warning` | Meaning |
|---|---|
| `EXCEL_NUMERIC_CELL` | The cell was a number, so a leading zero may have been dropped. Format the column as Text, or add the country code. |
| `EXCEL_PRECISION_LOST` | The cell holds more than 15 significant digits, which Excel rounds: the last digits are not reliable. |

The number is still validated and charged as usual; the warning is information. Text cells never carry one. `RUN_SUMMARY.excelWarnings` counts them.

#### Restarts and migrations

Apify may move a run to another server. The Actor saves rows in batches of 500 (and at least every 30 seconds, and when it is told to migrate or abort), charges **after** each batch is saved, and then records its progress. A restarted run reads that record and the dataset, skips what is already saved and never saves or charges a row twice. It reads the input again from the start to find its place (files are downloaded again, not charged), so a very large file can add a little time after a migration. If an input file has changed or become unreachable since the first attempt, the run stops with a message instead of guessing, and says nothing was charged twice.

### Pricing

**Pay per event: `number-validated` = $0.0003** per output row (valid or invalid).

| Numbers | Cost |
|---:|---:|
| 100 | $0.03 |
| 1,000 | $0.30 |
| 10,000 | $3.00 |
| 100,000 | $30.00 |
| 1,000,000 | $300.00 |

Not charged: blank lines, duplicates removed by "Remove duplicates", invalid numbers when "Output invalid numbers" is off, and every free row (file problems and refused web pages, cells over 1,000 characters, rows the dataset refused). Set Apify's **Max total charge** to cap a run; the Actor stops cleanly when it is reached (`stoppedBy: "max-charge"` in `RUN_SUMMARY`). Standard Apify platform costs for the run itself are covered by this price.

### Limits

- 1,000,000 numbers per run; 20 files per run, 50 MB each; downloads time out after 120 s by default (up to 600 s).
- CSV files are streamed. JSON and XLSX files are held in memory, so very large ones need more memory: at the default 512 MB, JSON up to about 30 MB and XLSX up to about 70 MB of sheet data are read; the run reports `FILE_TOO_LARGE_IN_MEMORY` otherwise. Raise the run memory or use CSV.
- Runs need at least 256 MB. For a million numbers with de-duplication, or files over about 20 MB, use 1,024 MB.
- After five failed files the remaining files are skipped, and after 1,000 cells over 1,000 characters the run stops: both are free but not unlimited.
- A CSV record (one row) may be up to 16 MB; an Excel row up to 16,384 columns.
- Numbers must be one per cell or line. Text around a number ("call 020 7946 0958 please") is not searched for numbers.
- Numbering plans change. Results reflect the rules in the bundled library version (`libphonenumber-js` 1.13.15, "max" metadata).

### Privacy and your responsibilities

In short:

1. **Only your own input is processed:** the numbers you type in, or a file you point the Actor to. It never searches for or collects numbers anywhere else.
2. **No lookups about any number:** validation runs offline (number-plan ranges and format). There is no carrier, HLR, owner, region or time-zone lookup, and no number is ever sent over the network.
3. **Nothing is kept beyond the run:** results go to your run's dataset; the run also writes `RUN_SUMMARY` and `PROGRESS` records with counts only. Numbers are never logged.

- Phone numbers are personal data. **You** supply them and you are the data controller under UK GDPR / GDPR; you are responsible for having a lawful basis, for telling the people concerned, and for lawful use of the results, for example **PECR (UK)** and **TCPA (US)** rules for calling or texting people, and any do-not-call registers. Validation does not give you consent to contact anyone.
- The Actor **never logs phone numbers** (logs contain counts only), makes **no network requests about them** (the only network access is optionally downloading a file you point it to), and stores nothing beyond this run's dataset, the `RUN_SUMMARY` record (counts, no numbers) and a `PROGRESS` record (counts, a hash of the input and a one-line outcome per file, no numbers) that lets a restarted run resume. Files are read once in memory and not kept. You control retention of the dataset through your Apify settings.
- File URLs are fetched with an SSRF guard: only `http(s)` to public addresses, re-checked on every redirect (at most 5), size and time capped. The Actor does not download from Google, YouTube or social platforms: upload those files instead. You are responsible for having the right to use your files.
- Key-value-store record links (`api.apify.com/v2/key-value-stores/…`, e.g. uploads) are read with the run's own token. The token is only ever sent to Apify's API, never to any other host.

### Use it via API, n8n or Make

**cURL (synchronous, returns the rows):**

```bash
curl -X POST "https://api.apify.com/v2/acts/ataism~phone-validator/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumbers": ["020 7946 0958", "+1 202-555-0143"], "defaultCountry": "GB"}'
```

**JavaScript (`apify-client`):**

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('ataism/phone-validator').call({
    phoneNumbers: ['020 7946 0958', '+1 202-555-0143'],
    defaultCountry: 'GB',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((i) => [i.e164, i.valid, i.type]));
```

**Python (`apify-client`):**

```python
from apify_client import ApifyClient

client = ApifyClient(token="APIFY_TOKEN")
run = client.actor("ataism/phone-validator").call(run_input={
    "phoneNumbers": ["020 7946 0958", "+1 202-555-0143"],
    "defaultCountry": "GB",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print([(i["e164"], i["valid"], i["type"]) for i in items])
```

**n8n:** add the Apify node, choose **Run an Actor and get dataset**, set the Actor to `ataism/phone-validator` and the input JSON as above.

**Make:** use the Apify modules **Run an Actor** (Actor `ataism/phone-validator`, input JSON as above), then **Get Dataset Items** with the run's default dataset ID.

### FAQ

**Does it tell me if a number is live or who owns it?** No. It validates format and number-plan ranges offline. For connectivity you need a carrier/HLR service, which this Actor does not call.

**Why is `+44 7700 900123` invalid?** It sits in a range that Ofcom reserves for TV and radio drama, which is deliberately not a real allocation. It has a possible length (`possible: true`) but no matching range (`INVALID_NUMBER`).

**Why does `type` say `FIXED_LINE_OR_MOBILE`?** In some plans (the US and Canada, for example) the number plan does not distinguish landlines from mobiles.

### Open-source components

`libphonenumber-js` (MIT; its metadata derives from Google's libphonenumber, Apache-2.0), `csv-parse` (MIT), `fflate` (MIT), Apify SDK (Apache-2.0).

# Actor input Schema

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

One number per line, in any common format (spaces, dashes, brackets, and an extension such as "ext. 12" are fine). Blank lines, and cells longer than 1,000 characters, are skipped and not charged. Numbers without a leading + use the default country below. The prefilled numbers are fictional or reserved ranges.

## `fileUrls` (type: `array`):

Direct http(s) links to a CSV/TSV, JSON, NDJSON or XLSX file with the numbers, one link per line (up to 20 files, 50 MB each). Private and local addresses are blocked, and so are Google and social platform links; upload the file instead. A link that returns a web page (a share link) instead of the file is refused, free. Name the column in "Column name" below.

## `files` (type: `array`):

Upload a CSV, JSON or XLSX file from your computer to a key-value store of your choice (the editor offers this), or paste a record URL. The Actor reads each file once and stores nothing.

## `column` (type: `string`):

The header (CSV, XLSX) or field name (JSON objects) that holds the phone numbers, matched without regard to case. A column number such as "2" also works for CSV and XLSX. Leave empty for a file with a single column, or a JSON array of strings.

## `sheetName` (type: `string`):

Which sheet of an XLSX workbook to read. Leave empty for the first sheet.

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

Two-letter ISO 3166-1 code, for example GB, US, DE, FR, AU, IN. Used for numbers written without a + and country code, such as 020 7946 0958. Without it, such numbers come back as INVALID_COUNTRY. Numbers that start with + never need it.

## `includeInternational` (type: `boolean`):

Adds the "international" field, for example +44 20 7946 0958.

## `includeNational` (type: `boolean`):

Adds the "national" field, for example 020 7946 0958 (as written inside the number's own country).

## `includeRfc3966` (type: `boolean`):

Adds the "rfc3966" field, for example tel:+442079460958, ready for a clickable link.

## `outputInvalid` (type: `boolean`):

On (default): every number gets a row, valid or not, with the reason when invalid, and every row is charged. Off: invalid numbers are left out of the dataset and not charged.

## `dedupe` (type: `boolean`):

Keeps the first occurrence of each number, compared by its E.164 form (so "020 7946 0958" and "+44 20 7946 0958" count as the same). Unparseable text is compared as typed. Dropped duplicates are not output and not charged.

## `maxNumbers` (type: `integer`):

Stops after this many non-blank numbers. The limit is 1,000,000 per run: a larger value is lowered with a warning.

## `downloadTimeoutSecs` (type: `integer`):

Per file, including redirects.

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

Internal: "selfTest" runs the maintainer health check and saves no items.

## Actor input object example

```json
{
  "phoneNumbers": [
    "+44 20 7946 0958",
    "020 7946 0321",
    "0161 496 0742",
    "0121 496 0503",
    "0117 496 0219",
    "0808 157 0192",
    "+44 7700 900123",
    "+1 202-555-0143",
    "+1 312-555-0178",
    "+61 2 5550 1234",
    "+61 491 570 006",
    "12345"
  ],
  "defaultCountry": "GB",
  "includeInternational": true,
  "includeNational": true,
  "includeRfc3966": true,
  "outputInvalid": true,
  "dedupe": false,
  "maxNumbers": 1000000,
  "downloadTimeoutSecs": 120,
  "mode": "run"
}
```

# Actor output Schema

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

One row per phone number with validity, E.164 and other formats, country, type and the reason when invalid (JSON, CSV, Excel or XML).

## `runSummary` (type: `string`):

Counts of valid and invalid numbers, duplicates dropped, rows charged, file problems and why the run stopped.

# 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": [
        "+44 20 7946 0958",
        "020 7946 0321",
        "0161 496 0742",
        "0121 496 0503",
        "0117 496 0219",
        "0808 157 0192",
        "+44 7700 900123",
        "+1 202-555-0143",
        "+1 312-555-0178",
        "+61 2 5550 1234",
        "+61 491 570 006",
        "12345"
    ],
    "defaultCountry": "GB"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ataism/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": [
        "+44 20 7946 0958",
        "020 7946 0321",
        "0161 496 0742",
        "0121 496 0503",
        "0117 496 0219",
        "0808 157 0192",
        "+44 7700 900123",
        "+1 202-555-0143",
        "+1 312-555-0178",
        "+61 2 5550 1234",
        "+61 491 570 006",
        "12345",
    ],
    "defaultCountry": "GB",
}

# Run the Actor and wait for it to finish
run = client.actor("ataism/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": [
    "+44 20 7946 0958",
    "020 7946 0321",
    "0161 496 0742",
    "0121 496 0503",
    "0117 496 0219",
    "0808 157 0192",
    "+44 7700 900123",
    "+1 202-555-0143",
    "+1 312-555-0178",
    "+61 2 5550 1234",
    "+61 491 570 006",
    "12345"
  ],
  "defaultCountry": "GB"
}' |
apify call ataism/phone-validator --silent --output-dataset

```

## MCP server setup

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