# Portugal Public Contracts (Portal BASE) (`pearlink/portugal-public-contracts-portal-base`) Actor

- **URL**: https://apify.com/pearlink/portugal-public-contracts-portal-base.md
- **Developed by:** [PearLink Systems Unipessoal](https://apify.com/pearlink) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 contract or announcement results

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 Public Contracts (Portal BASE)

Returns Portuguese public procurement from IMPIC's **Portal BASE** open data (2012 to today, refreshed weekly) as flat JSON rows: **signed contracts** (buyer and supplier with NIF/NIPC, CPV code, procedure type, price in EUR, signing date, link to the official record) or **announcements** (tender notices published in the Diário da República). Filters: buyer or supplier NIF/NIPC, CPV code prefix, date range, minimum value and keyword, plus a monitor mode that returns only results not seen in earlier runs. Contracts awarded to private individuals are excluded by default. Price: **$2.00 per 1,000 results**; error rows are free.

### What you can use it for

- **Find tenders and competitors**: which public bodies buy IT services (CPV `72`), from whom, and at what price.
- **Get alerts**: schedule monitor mode weekly, after IMPIC's refresh, and each run returns only results you haven't seen yet.
- **Do supplier due diligence**: list every public contract a company has won, using its NIPC.
- **Do journalism and research**: track direct awards (`Ajuste Direto Regime Geral`) above a value, by buyer or region.
- **Feed an AI agent**: through Apify's MCP server, an agent can ask "IT contracts over €100k signed by Lisbon municipality this year" and get structured rows back.

### Input

| Field                   | Default      | Description                                                                                                               |
| ----------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------- |
| `mode`                  | `search`     | `search` returns every match. `monitor` returns only results not returned by earlier monitor runs with the same filters.  |
| `recordType`            | `contract`   | `contract` (signed contracts, filtered by signing date) or `announcement` (tender notices, filtered by publication date). |
| `buyerNif`              | any          | Buyers' (contracting authorities') 9-digit NIF/NIPC.                                                                      |
| `supplierNif`           | any          | Suppliers' 9-digit NIF/NIPC (contracts only).                                                                             |
| `cpvPrefix`             | any          | CPV code prefixes, e.g. `72` (IT services), `45` (construction work).                                                     |
| `dateFrom` / `dateTo`   | last 90 days | `YYYY-MM-DD`.                                                                                                             |
| `minValueEur`           | none         | Minimum contract price (or base price, for announcements).                                                                |
| `keyword`               | none         | Must appear in the contract object or description. Case- and accent-insensitive.                                          |
| `excludeNaturalPersons` | `true`       | Skip contracts whose supplier is a private individual or has no Portuguese NIF. See [Personal data](#personal-data).      |
| `maxItems`              | `1000`       | Stop after this many results.                                                                                             |

IT contracts worth €100k or more, last 90 days:

```json
{
  "mode": "search",
  "recordType": "contract",
  "cpvPrefix": ["72"],
  "minValueEur": 100000,
  "maxItems": 10
}
```

More inputs that return results:

- One buyer (Município de Lisboa) this year: `{"buyerNif": ["500051070"], "dateFrom": "2026-01-01", "maxItems": 10}`
- Construction tenders over €1M: `{"recordType": "announcement", "cpvPrefix": ["45"], "minValueEur": 1000000, "maxItems": 10}`
- Every contract one supplier has won: `{"supplierNif": ["515615021"], "dateFrom": "2024-01-01", "maxItems": 10}`
- Keyword search: `{"keyword": "ciberseguranca", "dateFrom": "2026-01-01", "maxItems": 10}`

Invalid values, such as a NIF with a wrong check digit or an impossible date, are not dropped silently, because that would widen your search. The run instead returns a free row with `type: "error"` explaining the problem, and does not search.

### Output

```json
{
  "contractId": "12014814",
  "type": "contract",
  "publicationDate": "2025-12-04",
  "signingDate": "2026-02-23",
  "buyerName": "Serviços de Ação Social do Instituto Politécnico de Coimbra",
  "buyerNif": "600052737",
  "supplierName": "XpertGo - Business Solutions Development, Lda",
  "supplierNif": "515615021",
  "supplierIsCompany": true,
  "cpvCode": "72210000-0",
  "cpvDescription": "Serviços de programação de pacotes de software",
  "procedureType": "Ajuste Direto Regime Geral",
  "objectDescription": "Aquisição de serviços para obtenção de Selo de Usabilidade e Acessibilidade Digital Ouro na Página/Portal/App SASocial",
  "priceEur": 9000,
  "durationDays": 81,
  "location": "Portugal, Coimbra, Coimbra",
  "sourceUrl": "https://www.base.gov.pt/Base4/pt/detalhe/?type=contratos&id=12014814",
  "retrievedAt": "2026-10-12T15:20:00.000Z"
}
```

- `contractId` is stable: BASE's contract id for contracts, and the Diário da República (INCM) id for announcements.
- Consortia and multiple buyers are joined with `"; "`.
- `supplierIsCompany` is `true` when every supplier is a legal entity (by NIF, or by a legal form in the name), `false` when any supplier NIF belongs to a person, and `null` when unknown.
- Announcements have no supplier or signing date, and `sourceUrl` points to the Diário da República PDF.
- Every field is described in the Output tab.

### Pricing

You pay **$2 per 1,000 results** ($0.002 per contract or announcement returned), plus Apify's small per-run start fee. Error rows are free. If you set a maximum cost per run, the Actor stops cleanly at that limit and you get exactly the rows you paid for. In monitor mode, results cut off by the limit are delivered on the next run.

### Personal data

Most suppliers are companies, but some contracts go to private individuals or sole traders, whose names (and, rarely, NIFs) are personal data under the GDPR. With `excludeNaturalPersons` on (the default), the Actor skips any contract where a supplier:

- has a natural-person NIF (prefixes `1`, `2`, `3`, `45`, `8`), or
- has **no Portuguese NIF** and no legal form in its name. Portal BASE lists suppliers without a Portuguese NIF by name only, and most of them are private individuals. A name ending in a legal form, such as `Lda`, `S.A.`, `Unipessoal`, `S.L.`, `GmbH`, `Ltd`, `Inc` or `B.V.`, is treated as a company and kept.

In 2026 data, this skips about 10% of contracts, almost all of them awarded to private individuals. Foreign companies whose name carries no legal form are skipped too, because the Actor can't tell them apart from a person. Turn the option off only if you have a lawful basis to process personal data.

### Data source and licence

- Data comes from the Portal BASE datasets published by **IMPIC** (Instituto dos Mercados Públicos, do Imobiliário e da Construção) on [dados.gov.pt](https://dados.gov.pt/pt/datasets/contratos-publicos-portal-base-impic-contratos-de-2012-a-2026/). The licence is public domain ("Outra (Domínio Público)"), and IMPIC updates the data weekly. New contracts appear here after IMPIC's weekly refresh, not in real time.
- The Actor downloads the official open-data files. It does not scrape base.gov.pt.
- This Actor is not affiliated with or endorsed by IMPIC, base.gov.pt or the Diário da República.

### Related Actors

- [Portugal NIF, IBAN, Postcode & CAE Validator](https://apify.com/pearlink/portugal-nif-iban-postcode-cae-validator?ref=store-related): bulk-validate the NIFs and IBANs in your supplier list.
- [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

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

"search" returns every matching result. "monitor" returns only results not returned by earlier monitor runs with the same filters; schedule it weekly, after IMPIC's refresh.

## `recordType` (type: `string`):

"contract" = signed contracts (adjudicações), filtered by signing date. "announcement" = tender notices published in Diário da República, filtered by publication date.

## `buyerNif` (type: `array`):

Only records whose contracting authority has one of these 9-digit NIPCs, e.g. "600052737". Leave empty for any buyer.

## `supplierNif` (type: `array`):

Only contracts awarded to one of these suppliers (9-digit NIF/NIPC). Contracts only.

## `cpvPrefix` (type: `array`):

Only records with a CPV code starting with one of these digits, e.g. "72" for IT services or "45" for construction works.

## `dateFrom` (type: `string`):

Earliest signing date (contracts) or publication date (announcements), YYYY-MM-DD. Defaults to 90 days ago.

## `dateTo` (type: `string`):

Latest signing or publication date, YYYY-MM-DD. Defaults to today.

## `minValueEur` (type: `integer`):

Only records worth at least this much: contract price, or base price for announcements.

## `keyword` (type: `string`):

Text that must appear in the contract object or description. Case- and accent-insensitive ("automacao" matches "automação").

## `excludeNaturalPersons` (type: `boolean`):

Skip contracts whose supplier is a private individual or sole trader, or has no Portuguese NIF and no legal form (Lda, S.A., GmbH, Ltd...) in its name, since that name is most likely a person's. Their names and NIFs are personal data under the GDPR. Turn off only if you have a lawful basis to process them.

## `maxItems` (type: `integer`):

Stop after this many results.

## Actor input object example

```json
{
  "mode": "search",
  "recordType": "contract",
  "cpvPrefix": [
    "72"
  ],
  "minValueEur": 100000,
  "excludeNaturalPersons": true,
  "maxItems": 10
}
```

# Actor output Schema

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

One row per matching contract or announcement. Rows with type 'error' explain rejected input.

# 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 = {
    "cpvPrefix": [
        "72"
    ],
    "minValueEur": 100000,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("pearlink/portugal-public-contracts-portal-base").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 = {
    "cpvPrefix": ["72"],
    "minValueEur": 100000,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("pearlink/portugal-public-contracts-portal-base").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 '{
  "cpvPrefix": [
    "72"
  ],
  "minValueEur": 100000,
  "maxItems": 10
}' |
apify call pearlink/portugal-public-contracts-portal-base --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pearlink/portugal-public-contracts-portal-base"
        }
    }
}
```

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/bCmrtP2dcZJ5DLYd0/builds/HtAXzCwrdFhLRlHVK/openapi.json
