# Bulk Email, Phone, IBAN & BIC Validator (`bite-sized-insights/bulk-email-phone-iban-bic-validator`) Actor

Validate mixed lists of email addresses, phone numbers, IBANs and BICs in one run. Get a valid flag, a normalized value and type-specific details for every item. Offline structure checks for IBAN and BIC, with a default region for phone numbers.

- **URL**: https://apify.com/bite-sized-insights/bulk-email-phone-iban-bic-validator.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 $0.80 / 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 emails, phone numbers, IBANs and BICs in one bulk run - mix all four types in a single list and get one
uniform result per item: valid or not, a clean normalized value, and the type-specific details.***

Send a list of items, each with a `type` and a `value`, and get back a result for every one in the same order. Email
addresses are syntax-checked, normalized and tested for a mail server and disposable domains. Phone numbers are parsed
and checked against their country's numbering plan. IBANs and BICs are checked for structure, country and check
digits. Use one actor and one dataset instead of four separate cleanup jobs.

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

### Why Choose This Actor?

**"One list, one run, one result format - for every kind of contact and payment data you need to clean"**

Our Bulk Data Validator provides:

- **Four Types in One Run**: `email`, `phone`, `iban` and `bic` items can be mixed freely in the same input
- **Uniform Results**: every item returns the same six fields (`type`, `value`, `valid`, `normalized_value`, `data`,
  `error`), so you can filter on `valid` without knowing the type
- **Clean Normalized Values**: the normalized email address, the international phone format, the compact upper-case
  IBAN or BIC - ready to import
- **Type-Specific Details**: MX and disposable-domain checks for emails; formats, number type, carrier, location and
  time zones for phone numbers; country, check digits and bank parts for IBANs and BICs
- **Bad Items Never Stop the Run**: an unknown type or a missing value comes back as a result with an `error`
  message, not as a failed run
- **Cost-Effective**: Pay only for the items you validate: `$0.80 / 1k items`
- **No Third-Party Dependency**: no upstream service to fail or rate-limit you, and no API key to manage

### Quick Start

```json
{
  "items": [
    { "type": "email", "value": "jane@example.com" },
    { "type": "phone", "value": "020 7946 0958", "options": { "region": "GB" } },
    { "type": "iban", "value": "DE89 3704 0044 0532 0130 00" },
    { "type": "bic", "value": "DEUTDEFF500" },
    { "type": "iban", "value": "DE00 1234" }
  ]
}
```

### Usage Examples

#### Phone Numbers Without a Country Code

Set a default region for the whole run, and override it per item with `options.region`:

```json
{
  "items": [
    { "type": "phone", "value": "020 7946 0958" },
    { "type": "phone", "value": "030 123456", "options": { "region": "DE" } },
    { "type": "phone", "value": "+14155552671" }
  ],
  "default_region": "GB"
}
```

A number that starts with `+` always uses its own country code.

#### Clean Up a Supplier List

```json
{
  "items": [
    { "type": "email", "value": "accounts@supplier.example" },
    { "type": "iban", "value": "GB82 WEST 1234 5698 7654 32" },
    { "type": "bic", "value": "NWBKGB2L" }
  ]
}
```

### Output Example

Each item produces one dataset record. `data` depends on the type.

```json
{
  "type": "email",
  "value": "jane@example.com",
  "valid": true,
  "normalized_value": "jane@example.com",
  "data": {
    "email": "jane@example.com",
    "normalized_email": "jane@example.com",
    "syntax_valid": true,
    "domain_has_mx": true,
    "is_disposable": false,
    "is_role_account": false,
    "is_free_provider": false,
    "did_you_mean": null,
    "deliverable_likely": true,
    "reason": null
  },
  "error": null
}
```

```json
{
  "type": "phone",
  "value": "020 7946 0958",
  "valid": true,
  "normalized_value": "+44 20 7946 0958",
  "data": {
    "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
  },
  "error": null
}
```

```json
{
  "type": "iban",
  "value": "DE89 3704 0044 0532 0130 00",
  "valid": true,
  "normalized_value": "DE89370400440532013000",
  "data": {
    "iban": "DE89 3704 0044 0532 0130 00",
    "normalized_iban": "DE89370400440532013000",
    "formatted_iban": "DE89 3704 0044 0532 0130 00",
    "country_code": "DE",
    "check_digits": "89",
    "bban": "370400440532013000",
    "is_valid": true,
    "reason": null
  },
  "error": null
}
```

```json
{
  "type": "bic",
  "value": "DEUTDEFF500",
  "valid": true,
  "normalized_value": "DEUTDEFF500",
  "data": {
    "bic": "DEUTDEFF500",
    "normalized_bic": "DEUTDEFF500",
    "institution_code": "DEUT",
    "country_code": "DE",
    "location_code": "FF",
    "branch_code": "500",
    "is_valid": true,
    "reason": null
  },
  "error": null
}
```

An item that is processed but fails validation has `valid: false` and the explanation in `data.reason`:

```json
{
  "type": "iban",
  "value": "DE00 1234",
  "valid": false,
  "normalized_value": "DE001234",
  "data": {
    "iban": "DE00 1234",
    "normalized_iban": "DE001234",
    "formatted_iban": null,
    "country_code": null,
    "check_digits": null,
    "bban": null,
    "is_valid": false,
    "reason": "The number's checksum or check digit is invalid."
  },
  "error": null
}
```

### Input Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `items` | array | Yes | 1-100,000 objects `{type, value, options?}`; `type` is `email`, `phone`, `iban` or `bic` |
| `default_region` | string | No | Two-letter country code (e.g. `US`, `GB`) for phone numbers written without a `+` prefix |

`options` is optional. Phone items accept `{"region": "DE"}`, which overrides `default_region` for that item. Email,
IBAN and BIC items ignore options.

### Output Fields

| Field | Type | Description |
|-------|------|--------------|
| `type` | string | The item type as provided |
| `value` | string | The value exactly as provided in the input |
| `valid` | boolean | Email: likely deliverable. Phone, IBAN, BIC: passes validation. Always false when `error` is set |
| `normalized_value` | null/string | Email: normalized address. Phone: international format. IBAN, BIC: compact upper-case form. Null when it could not be parsed |
| `data` | object | The type-specific details below. Empty when `error` is set |
| `error` | null/string | Set only when the item could not be processed at all (unknown type, missing or non-text value, bad options) |

#### `data` for `email`

`email`, `normalized_email`, `syntax_valid`, `domain_has_mx`, `is_disposable`, `is_role_account`,
`is_free_provider`, `did_you_mean`, `deliverable_likely` (syntax valid, mail server found and not a disposable domain)
and `reason`. `is_disposable` is the disposable-email flag and feeds `deliverable_likely`. Role accounts such as
`support@` and free providers such as Gmail are flagged but do not affect `deliverable_likely`. `did_you_mean` is a
corrected full address when the domain looks like a typo of a popular provider (`john@gmial.com` ->
`john@gmail.com`), otherwise null.

#### `data` for `phone`

`phone_number`, `e164`, `international`, `national`, `rfc3966`, `country_code`, `region_code`, `is_possible`,
`possibility`, `is_valid`, `number_type`, `carrier`, `location`, `time_zones` and `reason`. Number type, carrier,
location and time zones are filled for valid numbers only.

#### `data` for `iban`

`iban`, `normalized_iban`, `formatted_iban` (groups of four), `country_code`, `check_digits`, `bban`, `is_valid` and
`reason`. The parts are filled for valid IBANs only.

#### `data` for `bic`

`bic`, `normalized_bic`, `institution_code`, `country_code`, `location_code`, `branch_code` (null for 8-character
codes), `is_valid` and `reason`. The parts are filled for valid BICs only.

### Pricing

| Cost | Description |
|------|-------------|
| $0.0001 / start | Charged per actor run |
| $0.80 / 1,000 items | Charged per item validated, whatever its type |

### API Integration

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/bite-sized-insights/validator-all/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"type": "email", "value": "jane@example.com"},
      {"type": "iban", "value": "DE89 3704 0044 0532 0130 00"}
    ]
  }'
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("bite-sized-insights/validator-all").call(
    run_input={
        "items": [
            {"type": "email", "value": "jane@example.com"},
            {"type": "phone", "value": "020 7946 0958", "options": {"region": "GB"}},
            {"type": "iban", "value": "DE89 3704 0044 0532 0130 00"},
        ]
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['type']} {item['value']}: valid={item['valid']} -> {item['normalized_value']}")
```

#### JavaScript

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

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

const run = await client.actor('bite-sized-insights/validator-all').call({
    items: [
        { type: 'email', value: 'jane@example.com' },
        { type: 'phone', value: '020 7946 0958', options: { region: 'GB' } },
        { type: 'iban', value: 'DE89 3704 0044 0532 0130 00' },
    ],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => {
    console.log(`${item.type} ${item.value}: valid=${item.valid} -> ${item.normalized_value}`);
});
```

### Use Cases

- **CRM and Lead Cleanup**: Check emails and phone numbers of an imported list in one pass
- **Supplier and Payee Onboarding**: Catch mistyped IBANs and BICs before a payment run bounces
- **Form and Signup Checks**: Batch-validate mixed contact and bank details collected through forms
- **Data Migration**: Normalize contact and bank fields to one clean format before loading them into a new system
- **Fraud Signals**: Flag disposable email domains, VoIP numbers or mismatched countries as a low-cost first pass

### FAQ

#### Does this check that a bank account or a phone number really exists?

No. IBANs and BICs are checked for length, country, structure and check digits, which catches typos and invented
numbers, but there is no bank or account lookup, so a well-formed IBAN may still belong to no account. Phone numbers
are checked against the numbering plan of their country; whether a number is currently assigned or reachable cannot
be known from that data. Emails are the one type with a live check: the domain is looked up for a mail server.

#### What makes an email "valid"?

`valid` is true when the address has correct syntax, its domain has a mail server and it is not a known disposable or
temporary email domain. Role accounts such as `info@` or `support@` are flagged in `data.is_role_account` but stay
valid, since they are often perfectly deliverable. The check does not contact the mailbox, so it cannot confirm that a
specific mailbox exists.

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

A number starting with `+` always uses its own country code. For other numbers, the `region` in the item's options is
used, then the run's `default_region`. Without either, the number cannot be interpreted and `data.reason` explains why.

#### What happens to an item with an unknown type or no value?

The run continues. That item gets a result with `valid: false`, empty `data` and an `error` message such as
`Unknown task type 'vat', expected one of: email, phone, iban, bic`, and it is counted like any other item.

#### Are the results in the same order as my input?

Yes. Result number N always belongs to item number N of the input, including items that returned an error.

#### Is my data 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 values against format and structure rules and, for email, a mail-server lookup. It does not
contact people, banks or carriers and cannot guarantee that an email, number or account is in use. Rules and data
change over time; results reflect the version of the actor you run.

***

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

# Actor input Schema

## `items` (type: `array`):

Items to validate. Each item is {"type", "value"} with a type of email, phone, iban or bic, and an optional "options" object (phone items accept {"region": "DE"}).

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

Optional two-letter country code (e.g. US, GB, DE) for phone numbers written without a + prefix. A region in an item's options overrides it.

## Actor input object example

```json
{
  "items": [
    {
      "type": "email",
      "value": "jane@example.com"
    },
    {
      "type": "phone",
      "value": "020 7946 0958",
      "options": {
        "region": "GB"
      }
    },
    {
      "type": "iban",
      "value": "DE89 3704 0044 0532 0130 00"
    },
    {
      "type": "bic",
      "value": "DEUTDEFF500"
    },
    {
      "type": "iban",
      "value": "DE00 1234"
    }
  ],
  "default_region": "US"
}
```

# Actor output Schema

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

Per-item results: validity, normalized value and type-specific details

# 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 = {
    "items": [
        {
            "type": "email",
            "value": "jane@example.com"
        },
        {
            "type": "phone",
            "value": "020 7946 0958",
            "options": {
                "region": "GB"
            }
        },
        {
            "type": "iban",
            "value": "DE89 3704 0044 0532 0130 00"
        },
        {
            "type": "bic",
            "value": "DEUTDEFF500"
        },
        {
            "type": "iban",
            "value": "DE00 1234"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bite-sized-insights/bulk-email-phone-iban-bic-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 = { "items": [
        {
            "type": "email",
            "value": "jane@example.com",
        },
        {
            "type": "phone",
            "value": "020 7946 0958",
            "options": { "region": "GB" },
        },
        {
            "type": "iban",
            "value": "DE89 3704 0044 0532 0130 00",
        },
        {
            "type": "bic",
            "value": "DEUTDEFF500",
        },
        {
            "type": "iban",
            "value": "DE00 1234",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("bite-sized-insights/bulk-email-phone-iban-bic-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 '{
  "items": [
    {
      "type": "email",
      "value": "jane@example.com"
    },
    {
      "type": "phone",
      "value": "020 7946 0958",
      "options": {
        "region": "GB"
      }
    },
    {
      "type": "iban",
      "value": "DE89 3704 0044 0532 0130 00"
    },
    {
      "type": "bic",
      "value": "DEUTDEFF500"
    },
    {
      "type": "iban",
      "value": "DE00 1234"
    }
  ]
}' |
apify call bite-sized-insights/bulk-email-phone-iban-bic-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bite-sized-insights/bulk-email-phone-iban-bic-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/QvVO2r10jhxdDFot3/builds/qdlD2wUu6uBjkUHQT/openapi.json
