# Portugal NIF, IBAN, Postcode & CAE Validator (`pearlink/portugal-nif-iban-postcode-cae-validator`) Actor

One input item checked and returned as a dataset row, valid or not.

- **URL**: https://apify.com/pearlink/portugal-nif-iban-postcode-cae-validator.md
- **Developed by:** [PearLink Systems Unipessoal](https://apify.com/pearlink) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 result items

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

## Portugal NIF, IBAN, Postcode & CAE Validator

Returns one row per input value saying whether it is a valid Portuguese **NIF/NIPC** tax number, **IBAN** (any country), Portuguese **postcode** (código postal) or **CAE-Rev.4** activity code, with its normalized form and the facts it encodes: taxpayer entity type (person, company, public body, fund…), bank and branch code, or the official CAE designation. Input is a list of up to 100,000 strings, auto-detected or forced to one kind. Source: check-digit algorithms plus the official CAE-Rev.4 list (Decreto-Lei n.º 9/2025); no external calls, nothing stored. Price: **$0.50 per 1,000 items**, valid or not.

### What you can use it for

- **Clean a CRM or supplier list** before importing it: catch mistyped NIFs and IBANs, normalize `PT 500.000.000` to `500000000`.
- **Tell companies from people**: the NIF prefix shows whether a taxpayer is a natural person, a company, a public body, an estate or an investment fund. Useful for GDPR filtering.
- **Check payment details** before a SEPA transfer: mod-97 checksum for every country, plus the Portuguese NIB check digits and bank/branch codes for PT IBANs.
- **Map CAE codes to activity names** using the official CAE-Rev.4 list (in force since 1 January 2025).
- **Let an AI agent validate data** through Apify's MCP server: send a list, read back structured rows.

### Input

| Field   | Type     | Description                                                                                                                   |
| ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `items` | string\[] | Values to validate, up to 100,000. Spaces and dots are ignored. Send values as strings so leading zeros in CAE codes survive. |
| `kind`  | string   | `auto` (default) detects each item's kind from its shape. Or force `nif`, `iban`, `postcode` or `cae`.                        |

```json
{
  "items": ["123456789", "PT50 0002 0123 1234 5678 9015 4", "1000-001", "62100"],
  "kind": "auto"
}
```

More inputs that return results:

- Supplier NIFs, one invalid: `{"items": ["500051070", "600052737", "PT 515 615 021", "500000001"], "kind": "nif"}`
- IBANs from several countries: `{"items": ["PT50000201231234567890154", "DE89370400440532013000", "GB82WEST12345698765432"], "kind": "iban"}`
- Every CAE level: `{"items": ["J", "62", "621", "6210", "62100"], "kind": "cae"}`

### Output

One dataset row per input item, in input order.

```json
[
  {
    "input": "123456789",
    "kind": "nif",
    "valid": true,
    "normalized": "123456789",
    "details": { "entityType": "natural-person", "isNaturalPerson": true },
    "error": null
  },
  {
    "input": "PT50 0002 0123 1234 5678 9015 4",
    "kind": "iban",
    "valid": true,
    "normalized": "PT50000201231234567890154",
    "details": { "country": "PT", "bankCode": "0002", "branchCode": "0123" },
    "error": null
  },
  {
    "input": "1000-001",
    "kind": "postcode",
    "valid": true,
    "normalized": "1000-001",
    "details": { "formatOnly": true },
    "error": null
  },
  {
    "input": "62100",
    "kind": "cae",
    "valid": true,
    "normalized": "62100",
    "details": {
      "revision": "CAE-Rev.4",
      "level": "subclass",
      "designation": "Atividades de programação informática"
    },
    "error": null
  },
  {
    "input": "500000001",
    "kind": "nif",
    "valid": false,
    "normalized": "500000001",
    "details": null,
    "error": "Invalid NIF check digit"
  }
]
```

| Field        | Meaning                                                                                   |
| ------------ | ----------------------------------------------------------------------------------------- |
| `input`      | The item exactly as you sent it.                                                          |
| `kind`       | `nif`, `iban`, `postcode`, `cae`, or `unknown` when auto-detection could not classify it. |
| `valid`      | `true` when every check for that kind passed.                                             |
| `normalized` | Canonical form (NIF as 9 digits, IBAN uppercase without spaces, CAE without dots).        |
| `details`    | Kind-specific facts, see below. `null` for invalid items.                                 |
| `error`      | Why the item is invalid, in English. `null` for valid items.                              |

#### What each kind checks

- **NIF/NIPC**: 9 digits and the mod-11 check digit. `entityType` comes from the prefix: `1`, `2`, `3` natural person; `45` non-resident natural person; `8` sole trader (old series); `5` legal person; `6` public administration; `70`, `74`, `75` undivided estate; `71` non-resident legal person; `72` investment fund; `77`, `78`, `79` special tax-authority series; `90`, `91` condominium or irregular company; `98` non-resident without establishment; `99` civil company without legal personality.
- **IBAN**: ISO 13616 format and mod-97 checksum for any country. Portuguese IBANs also get a length check (25), a NIB check-digit check, and `bankCode` / `branchCode`. Other countries' lengths are not checked individually.
- **Postcode**: format `NNNN-NNN` only. The Actor does **not** confirm that the postcode exists (`details.formatOnly` is always `true`), because the CTT postcode database is not openly licensed.
- **CAE**: the code must exist in CAE-Rev.4 at any level: section (`J`), division (`62`), group (`621`), class (`6210`) or subclass (`62100`). `details` gives the level and the official Portuguese designation.

### Pricing

You pay **$0.50 per 1,000 items** ($0.0005 per item), valid or invalid, plus Apify's small per-run start fee. If you set a maximum cost for the run, the Actor stops cleanly at that limit, and you get exactly the rows you paid for.

### Data sources and licence

- NIF, IBAN and postcode checks are algorithms; no external data is used. The NIF prefix table follows the Autoridade Tributária / RNPC series.
- The CAE-Rev.4 list is extracted from the annex of [Decreto-Lei n.º 9/2025](https://diariodarepublica.pt/dr/detalhe/decreto-lei/9-2025-907097147), as published by INE in its metadata system ([SMI, version 5497](https://smi.ine.pt/Versao/Detalhes/5497)). Official legislative texts are not protected by copyright in Portugal (Código do Direito de Autor, art. 8.º).
- This Actor is not affiliated with or endorsed by the Autoridade Tributária, INE, Banco de Portugal or CTT.
- No input data is stored beyond your own run's dataset, and nothing you send is logged.

### Related Actors

- [Portugal Public Contracts (Portal BASE)](https://apify.com/pearlink/portugal-public-contracts-portal-base?ref=store-related): contracts and announcements from Portal BASE, with supplier NIFs validated by this Actor's logic.
- [Portugal Housing & Interest Rates Feed](https://apify.com/pearlink/portugal-housing-interest-rates-feed?ref=store-related): house prices, rents and mortgage rates from INE and Banco de Portugal, plus ECB interest rates, in one tidy time-series format.

# Actor input Schema

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

Values to validate, one per entry: Portuguese NIF/NIPC (e.g. "123456789" or "PT123456789"), IBAN (any country; PT gets extra checks), postcode ("1000-001") or CAE-Rev.4 code ("62100", "6210", "J"). Spaces and dots are ignored. Send values as strings so leading zeros in CAE codes survive. Maximum 100,000 per run.

## `kind` (type: `string`):

What the items are. "auto" detects each item's kind from its shape; set an explicit kind when all items are the same type, so a malformed value is reported against that type instead of as "unknown".

## Actor input object example

```json
{
  "items": [
    "123456789",
    "PT50 0002 0123 1234 5678 9015 4",
    "1000-001",
    "62100"
  ],
  "kind": "auto"
}
```

# Actor output Schema

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

One row per input item, in input order, with validity, normalized value and 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": [
        "123456789",
        "PT50 0002 0123 1234 5678 9015 4",
        "1000-001",
        "62100"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pearlink/portugal-nif-iban-postcode-cae-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": [
        "123456789",
        "PT50 0002 0123 1234 5678 9015 4",
        "1000-001",
        "62100",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pearlink/portugal-nif-iban-postcode-cae-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": [
    "123456789",
    "PT50 0002 0123 1234 5678 9015 4",
    "1000-001",
    "62100"
  ]
}' |
apify call pearlink/portugal-nif-iban-postcode-cae-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pearlink/portugal-nif-iban-postcode-cae-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/E45qZr1uRRW6XVh7C/builds/fVSuSdkkpKyyoIKoW/openapi.json
