# Address Verification API - Global Cleanse and Geocode (`nabeelbaghoor/address-verification-api`) Actor

Verify and standardise postal addresses in 245 countries with a match grade per address, plus email verification with a risk score, phone validation with network and number type, forward and reverse geocoding, and UK bank account checks. Pay per result.

- **URL**: https://apify.com/nabeelbaghoor/address-verification-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Business, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 results

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?

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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Address Verification API - Global Cleanse and Geocode

Turn the addresses, email addresses and phone numbers you already hold into ones you can actually ship to, mail to and call. Eight services over one key, 245 countries, one flat row per result.

### What this actor does

- **Verifies and corrects addresses in 245 countries.** Every address comes back standardised into its parts - building, sub-building, street, locality, region, postal code, country - with the local format and script respected rather than forced into a single layout.
- **Grades every match rather than passing or failing it.** The provider returns a compound verification code whose leading character says how well the address matched, and the actor lifts that out as both a plain number and a readable label. That is the difference between "verified to the exact premise" and "we found the street", and shipping decisions turn on it.
- **Keeps every candidate for an ambiguous address.** When one input matches several real addresses, each candidate is written as its own row. Collapsing an ambiguous address to its first candidate is how the wrong address gets quietly chosen for you.
- **Separates searching from retrieving, and says so.** Type-ahead search narrows a partial string and costs nothing; turning the result into a full address is what gets charged. Search results are also often containers - a postcode, a street, a building - which have to be searched into rather than used, and the actor follows them down automatically. You can also run search with retrieval off, which costs nothing and hands you identifiers to retrieve later.
- **Verifies email addresses with a risk level, not just a verdict.** Valid, catch-all, invalid or timed out, plus a low, medium or high estimate of how likely the address is to bounce, plus a disposable-mailbox flag. Batches of up to a hundred, or one at a time when a per-address timeout matters.
- **Says plainly when an email verdict proves nothing.** A catch-all result means the domain accepts mail for every possible mailbox, so a positive answer there says nothing about the individual address. It is returned as its own verdict rather than folded into valid.
- **Validates phone numbers against the live network.** Number type, network operator, network country, national format, and whether the number has been ported or is currently roaming. The provider also distinguishes "could not reach the network" from "bad number", and so does the output.
- **Geocodes in both directions.** Place names and postal codes into coordinates, coordinates into places, with a bad coordinate pair dropped before the request rather than sent and charged for.
- **Checks UK bank accounts.** Account number and sort code, in either order, returning the bank and branch and whether the account takes faster payments, direct debits and CHAPS.
- **Waits out a protective throttle instead of failing.** This provider trips a surge protector on unusually heavy traffic, and it clears on its own. That is retried rather than reported, which is what keeps a long batch alive.
- **Tells five kinds of refusal apart.** An unknown key, an empty balance, a spent daily limit, a key restricted by URL, IP or service, and a malformed request all arrive as the same shape here. They need five different reactions and the actor gives them five.
- **Never charges for a miss.** Only rows carrying a resolved result are billed.

### Input

| Field | What it does |
| --- | --- |
| `mode` | Which of the eight services to call. |
| `addresses` | Addresses to verify, as text or JSON objects. |
| `searches` | Partial addresses to search for. |
| `addressIds` | Identifiers from an earlier search, to retrieve. |
| `emails` | Email addresses to verify. |
| `phones` | Phone numbers to verify. |
| `locations` | Places or postal codes to geocode. |
| `coordinates` | Coordinate pairs to reverse geocode. |
| `bankAccounts` | UK sort code and account number pairs. |
| `countries` | Restrict searches to these countries. |
| `defaultCountry` | Country to assume when an input does not say. |
| `geocode` | Return coordinates alongside verified addresses. |
| `minVerificationLevel` | Keep only addresses matched at least this well. |
| `maxMatchesPerAddress` | Candidate matches allowed per ambiguous address. |
| `outputCasing` | How verified addresses are cased. |
| `outputScript` | Script verified addresses are transliterated into. |
| `retrieveAddresses` | Retrieve the full address after a search. |
| `followContainers` | Search inside partial matches. |
| `searchLimit` | Results returned per search query. |
| `language` | Language code for the search mode. |
| `findTypes` | Keep only these kinds of search result. |
| `emailResponseCodes` | Keep only these email verdicts. |
| `emailRiskLevels` | Keep only these email risk levels. |
| `excludeDisposableEmail` | Drop throwaway mailboxes. |
| `emailTimeoutMs` | Milliseconds allowed per email address. |
| `phoneNumberTypes` | Keep only mobiles, landlines or VoIP. |
| `requireValidPhone` | Keep only confirmed numbers. |
| `forceSingle` | Verify email addresses one at a time. |
| `batchSize` | Records per request, up to one hundred. |
| `requestsPerMinute` | Pace the run under your plan's rate limit. |
| `skipNotFound` | Leave inputs with no result out of the dataset. |
| `maxResults` | Hard cap on rows, and therefore on spend and run time. |
| `apiKey` | Your own API key. Stored as a secret. |

### Example output

```json
{
  "found": true,
  "mode": "address-verify",
  "query": "10 Downing Street, London, SW1A 2AA, GB",
  "inputId": "0",
  "addressVerificationCode": "V44-I44-P6-100",
  "verificationLevel": 5,
  "verificationMatch": "Verified",
  "addressQualityIndex": "A",
  "addressComplete": "10 Downing Street\nLondon\nSW1A 2AA\nUnited Kingdom",
  "addressLine1": "10 Downing Street",
  "buildingNumber": "10",
  "street": "Downing Street",
  "locality": "London",
  "administrativeArea": null,
  "postalCode": "SW1A 2AA",
  "country": "United Kingdom",
  "countryIso2": "GB",
  "countryIso3": "GBR",
  "latitude": 51.5034,
  "longitude": -0.1276,
  "geoAccuracy": "P4",
  "deliveryPointSuffix": "1A",
  "matchedFields": "BSPCZ",
  "error": null,
  "raw": { }
}
```

### Frequently asked questions

#### What is the difference between verifying an address and searching for one?

Verifying takes an address you already hold, corrects it, standardises it and tells you how well it matched. Searching is for an address you do not have yet: you type a fragment, the service narrows it, and you end up with an identifier that has to be retrieved to become a real address. They also cost differently. Searching is free and retrieving is charged, which is why a run that only searches spends nothing and collects no addresses, and why this actor retrieves by default.

#### What does the verification code actually mean?

It is a compound string, and its first character is the part that matters: verified, partially verified, ambiguous, unverified, reverted or conflict, followed by digits grading the individual components. The actor lifts that leading character out as both a readable label and a number from one to five, so you can filter on it without parsing a string. Set the minimum verification level to five when only exact premise matches will do, and to three or four when a street-level match is good enough.

#### Why would one address come back as several rows?

Because it genuinely matches several real addresses. A street with no building number, or a building with unlisted sub-units, has more than one correct resolution, and the provider returns all of them. Each candidate is written as its own row rather than collapsed to the first one, since silently choosing among them is how a parcel ends up at the wrong flat. Use the maximum matches setting to cap how many candidates one input may produce.

#### What is a catch-all email result and why is it separate from valid?

A catch-all domain is configured to accept mail addressed to every possible mailbox, whether or not it exists. Checking any address there comes back positive and proves nothing about the individual mailbox. This provider returns that as its own verdict rather than folding it into valid, and this actor keeps that distinction, because treating it as valid is how a list that looks clean still bounces.

#### What does the phone check tell me beyond valid or invalid?

The number type, so a messaging campaign can keep the mobiles and a call list can keep the landlines; the network operator and the country that network is in; the national format for display; and whether the number has been ported to another network or is currently roaming abroad. It also has a third verdict beyond yes and no, meaning the network could not be reached, which is not the same as a bad number and should not be filtered out as one.

#### Can I search without spending anything?

Yes. Turn retrieval off and the search mode writes the identifiers and descriptions it found without turning any of them into full addresses. Searching is free on this provider, so that run costs nothing, and the identifiers can be fed into the retrieve mode later. Note that the provider does watch the ratio between the two and will eventually object to a very large number of searches with no retrievals behind them.

#### Why does batching addresses by country matter?

Because the provider's own guidance is to keep one batch to one country where you can. Its verification engine loads reference data per country, and a batch mixing twenty countries makes it work far harder than a batch of a hundred addresses all in one. The batch ceiling is a hundred records either way; grouping by country before you run is free and noticeably faster.

#### My key works elsewhere but is refused here. Why?

Keys on this provider carry their own security settings: a key can be restricted to particular URLs, particular IP addresses, particular services, or a daily lookup limit, and any of those will refuse a request that is otherwise perfectly valid. The actor reports each of these separately rather than as one generic rejection, so the message tells you which restriction was hit. An unknown key, an empty balance, a spent daily limit and a service restriction are four different problems with four different fixes.

#### Do I need my own API key?

Yes. This actor does not include data access. You use your own API key from Loqate, which is the provider whose address verification API this actor calls, created in your account there. Your own plan, credit balance and terms apply. Paste the key into the `apiKey` field, where it is stored as an Apify secret. Keys look like AA11-AA11-AA11-AA11.

#### What happens when an input returns nothing?

An invalid email address or an unverifiable address is a verdict, not a miss: the provider telling you the input is bad is the question you asked, so that row is written and billed like any other. A miss is an input the provider returned no result for at all, and those are written with `found: false` and never billed. Set `skipNotFound` to true to leave them out of the dataset entirely.

#### How much does a run cost?

Pricing is pay per result: you are charged for each result written to the dataset, and never for misses, for rows dropped by the filters, or for duplicates. Note that an ambiguous address returning three candidates is three rows, and that a search drilling into a postcode can return every address inside it, so the maximum results cap is doing real work in those modes. Apify platform usage is included in the per-result price. Your own API provider's credit balance is separate and billed by them.

### Keyword map

address verification API, address validation API, global address verification, international address cleansing, address standardisation, address autocomplete, address capture, type-ahead address search, postal address correction, delivery point validation, address geocoding, reverse geocoding API, latitude longitude lookup, postcode lookup, email verification API, email validation, catch-all detection, disposable email detection, email risk score, phone validation API, phone number lookup, mobile or landline detection, number porting check, roaming check, UK bank account validation, sort code check, modulus check, checkout address validation, data quality API, CRM address hygiene

# Actor input Schema

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

Which service to call. Each mode reads a different input list, so fill in the list named in the mode you pick and leave the others empty.

## `addresses` (type: `array`):

Addresses to verify, one per line. A whole address written as plain text works, and so does a JSON object with any of these fields: address, address1 to address5, organization, building, premise, subBuilding, thoroughfare, locality (or city), dependentLocality, administrativeArea (or state), subAdministrativeArea, superAdministrativeArea, postalCode (or zip), postBox, country, contact, department, latitude, longitude. Supplying a country raises the match rate considerably.

## `searches` (type: `array`):

Partial addresses to search for, one per line, used by the search mode. Searching costs nothing and returns identifiers, and turning an identifier into a full address is the step that is charged.

## `addressIds` (type: `array`):

Address identifiers from an earlier search, one per line, used by the retrieve mode. This is how a run picks up where a search left off without paying for the search again.

## `emails` (type: `array`):

Addresses to verify, one per line. An address pasted inside a longer string is extracted before the request, and duplicates are removed so you are never charged twice for the same address.

## `phones` (type: `array`):

Numbers to verify, one per line. Include the country code, or set a default country below so numbers written in national format still resolve.

## `locations` (type: `array`):

Place names or postal codes to turn into coordinates, one per line. Set a default country to keep a name that exists in several countries from resolving to the wrong one.

## `coordinates` (type: `array`):

Coordinate pairs to turn into places, one per line, written as latitude then longitude. Pairs outside the valid range are dropped before the request rather than sent and charged for.

## `bankAccounts` (type: `array`):

United Kingdom accounts to verify, one per line, written as a sort code and an account number in either order. The two are told apart by length, so any separator works.

## `countries` (type: `array`):

Two-letter or three-letter country codes, used by the search mode to keep results inside the countries you care about. Leave empty to search everywhere.

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

The country to assume when an input does not say. Used by address verification, phone verification and geocoding. A phone number in national format and a postal code that exists in several countries both need this to resolve correctly.

## `geocode` (type: `boolean`):

Ask the address verification service for latitude and longitude alongside the corrected address. Off by default because it can cost more of your provider credits.

## `minVerificationLevel` (type: `integer`):

Only keep addresses matched at least this well, on a five point scale where five is fully verified, four is partially verified, three is ambiguous and below that is unverified. Sent to the provider as well as applied locally, so it genuinely narrows the results. Leave at zero to keep every level.

## `maxMatchesPerAddress` (type: `integer`):

How many candidate matches the verification service may return for one ambiguous address. Every candidate is a row, so this multiplies both the dataset and the spend. Leave empty for the provider's own default.

## `outputCasing` (type: `string`):

How verified addresses are cased on the way out, such as Title, Upper or Lower. Leave empty for the provider's own default.

## `outputScript` (type: `string`):

The script verified addresses are transliterated into, such as Latn for Latin or Native to keep the local script. Leave empty for the provider's own default.

## `retrieveAddresses` (type: `boolean`):

In the search mode, turn each matched address identifier into the full address. On by default, because a search on its own returns identifiers rather than addresses. Turning it off makes a run free and gives you identifiers to retrieve later.

## `followContainers` (type: `boolean`):

A search can return a street, a postcode or a building rather than an address, and those have to be searched into rather than used. On by default, which is what turns a postcode into the addresses inside it. Searching is free, so this costs nothing until an address is actually retrieved.

## `searchLimit` (type: `integer`):

How many results one search returns before the run starts retrieving them. Raising it widens the net and, with retrieval on, multiplies the spend.

## `language` (type: `string`):

A three letter language code for the search mode. Be careful with this: filtering by a language the search term is not written in returns nothing at all rather than falling back.

## `findTypes` (type: `array`):

When search results are written directly rather than retrieved, keep only these kinds. Leave empty to keep every kind.

## `emailResponseCodes` (type: `array`):

Only keep addresses with these verdicts. Note that a catch-all result means the domain accepts everything, so the individual mailbox is unproven rather than confirmed. Leave empty to keep every verdict.

## `emailRiskLevels` (type: `array`):

Only keep addresses the provider rated this way. The risk level aggregates every signal it holds into a single estimate of how likely the address is to bounce.

## `excludeDisposableEmail` (type: `boolean`):

Leave out addresses on throwaway or temporary mailbox providers, which are created to expire and are worth nothing in a list.

## `emailTimeoutMs` (type: `integer`):

How long the provider may spend on one address, from one to fifteen thousand milliseconds. Below about five thousand you will see noticeably more timeout verdicts, which cost you a lookup and tell you nothing.

## `phoneNumberTypes` (type: `array`):

Only keep numbers of these kinds. Useful when a campaign needs mobiles for messaging or landlines for a call list.

## `requireValidPhone` (type: `boolean`):

Drop numbers the provider could not confirm. Note that this also drops the inconclusive answer the provider returns when the network could not be reached, which is not the same as a bad number.

## `forceSingle` (type: `boolean`):

Send every address as its own request rather than in batches of up to one hundred. Slower and far more requests, and the only route that honours a per address timeout. The actor already uses it automatically for very short lists.

## `batchSize` (type: `integer`):

How many addresses or email addresses to submit in one request, up to the provider's ceiling of one hundred. The provider's own advice is to keep an address batch to one country at a time, which lets its engine work far more efficiently.

## `requestsPerMinute` (type: `integer`):

Pace the run so it stays under whatever rate your plan allows. Lower this if the provider's surge protector starts tripping; raise it to finish a long list sooner.

## `skipNotFound` (type: `boolean`):

Leave inputs the provider returned nothing for out of the dataset. Note that an invalid email address is a verdict, not a miss, so this does not drop invalid rows. Off by default. Misses are never charged for either way.

## `maxResults` (type: `integer`):

Stop after this many rows. This is the cap on both spend and run time, and it matters most in the search mode, where one query can drill into a postcode holding dozens of addresses.

## `apiKey` (type: `string`):

Your own API key for the address verification API. Keys look like AA11-AA11-AA11-AA11 and carry their own security settings, so a key restricted to a URL, an IP address or a subset of services will be refused for anything outside them. Stored as a secret.

## Actor input object example

```json
{
  "mode": "address-verify",
  "addresses": [
    "10 Downing Street, London, SW1A 2AA, GB"
  ],
  "geocode": false,
  "minVerificationLevel": 0,
  "retrieveAddresses": true,
  "followContainers": true,
  "searchLimit": 10,
  "findTypes": [],
  "emailResponseCodes": [],
  "emailRiskLevels": [],
  "excludeDisposableEmail": false,
  "emailTimeoutMs": 5000,
  "phoneNumberTypes": [],
  "requireValidPhone": false,
  "forceSingle": false,
  "batchSize": 100,
  "requestsPerMinute": 300,
  "skipNotFound": false,
  "maxResults": 100
}
```

# Actor output Schema

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

One row per result, carrying the corrected address with its match grade and coordinates, the email verdict with its risk level, the phone number with its network and type, a geocoded place, or a UK bank account verdict.

# 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 = {
    "addresses": [
        "10 Downing Street, London, SW1A 2AA, GB"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/address-verification-api").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 = { "addresses": ["10 Downing Street, London, SW1A 2AA, GB"] }

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/address-verification-api").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 '{
  "addresses": [
    "10 Downing Street, London, SW1A 2AA, GB"
  ]
}' |
apify call nabeelbaghoor/address-verification-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/address-verification-api"
        }
    }
}

```

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/yjFa7RDAqEKpBiwFI/builds/Nuq2GPlbzd38vl6vC/openapi.json
