# Romanian Public Contracts Scraper (e-licitatie.ro / SEAP) (`darknezz/ro-public-contracts-scraper`) Actor

Scrape Romanian public procurement from e-licitatie.ro (SEAP/ANAP): tender notices and awarded contracts. Filter by keyword, CPV code, date range and contracting authority. Includes contract values in RON, deadlines and winners.

- **URL**: https://apify.com/darknezz/ro-public-contracts-scraper.md
- **Developed by:** [Oaida Adrian](https://apify.com/darknezz) (community)
- **Categories:** Business, Automation, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 company looked ups

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/platform/actors/running/actors-in-store#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

## Romanian Public Contracts Scraper (e-licitatie.ro / SEAP)

Scrape **Romanian public procurement** — tenders and awarded contracts — from
**e-licitatie.ro**, the official national platform run by ANAP (Agenția
Națională pentru Achiziții Publice), the successor to SEAP. Filter by keyword,
CPV code, publication date and contracting authority. Get contract values in
RON, deadlines, statuses and **winners** for awarded contracts.

All data comes from the platform's own public JSON API — no login, no cookies,
no browser required.

### Why scrape Romanian public procurement?

Romania publishes every public tender and every awarded contract on
e-licitatie.ro. That is a massive, structured stream of business intelligence:

- **Sales intelligence** — find authorities buying exactly what you sell, with
  deadlines and budget ceilings, weeks before the award.
- **Competitive analysis** — see who wins contracts in your niche, at what
  price (winner + awarded value in RON for every published award).
- **Market research** — track CPV categories over time, estimate market size,
  watch infrastructure, IT, health, agriculture spending.
- **Journalism & research** — monitor public money flows, detect award
  patterns, build datasets for analysis.

The native-language advantage: titles and descriptions are in Romanian, and
the CPV classification matches EU-wide coding, so you can join with EU TED
data.

### How it works

1. Build a filter: free-text keyword (Romanian), CPV code/prefix, publication
   date range (YYYY-MM-DD), contracting authority (partial name), and mode.
2. The actor queries the public search API
   (`POST /api-pub/NoticeCommon/GetCNoticeListFiltered/` for tenders,
   `POST /api-pub/NoticeCommon/GetCANoticeList/` for awarded contracts) with
   the same headers the web app sends (Referer + Origin + X-Requested-With —
   the API rejects hotlink requests without them).
3. With `fetchDetails` on (default), each result is enriched from the notice
   view endpoints: full description, authority contact details, CPV name, and
   — for awarded contracts — the **winner** and **awarded value** via
   `C_PUBLIC_CANotice` + `GetCANoticeContracts`.
4. Results are pushed to the default dataset as JSON.

### Input

| Field | Type | Description |
|---|---|---|
| `keyword` | string | Free text in the contract title/object (e.g. `infrastructura`, `drumuri`, `medicamente`). Empty = latest notices. |
| `cpvCode` | string | CPV code or prefix (e.g. `45233140-2` or `45233100`). |
| `dateFrom` / `dateTo` | string | Publication date range, `YYYY-MM-DD`. |
| `authority` | string | Contracting authority partial name (e.g. `Primaria`, `Consiliul Local`). |
| `mode` | string | `tenders` (participation notices, default), `awarded` (contract awards with winners), or `both`. |
| `fetchDetails` | bool | Enrich each notice with description, authority contact and winners. Default `true`. |
| `maxItems` | int | Max results to return (default 50, max 500). |

Example input:

```json
{
  "keyword": "drumuri",
  "cpvCode": "45233140-2",
  "dateFrom": "2026-01-01",
  "mode": "both",
  "maxItems": 100
}
```

### Output

One dataset item per notice. Key fields:

| Field | Description |
|---|---|
| `contractId` | Internal notice/contract ID (`cNoticeId` / `caNoticeId`). |
| `noticeNo` | Public notice number (e.g. `CN1047952`, `SCNA1135873`). |
| `title` | Contract title (Romanian). |
| `description` | Short description of the object (when `fetchDetails`). |
| `authority` | Contracting authority name (with CUI/fiscal prefix). |
| `authorityCui` | Authority fiscal number (CUI). |
| `cpvCode` | CPV code + name (e.g. `45233140-2 - Lucrari de drumuri`). |
| `acquisitionType` | Furnizare / Servicii / Lucrari. |
| `procedureType` | Licitatie deschisa, Procedura simplificata, etc. |
| `estimatedValueRon` | Estimated value in RON (tenders). |
| `contractValueRon` | Awarded value in RON (awarded contracts). |
| `publicationDate` | Notice publication timestamp. |
| `deadline` | Tender receipt deadline (tenders). |
| `awardDate` | Award date (awarded contracts). |
| `status` | Procedure/notice state (Publicat, Atribuita, Anulata...). |
| `winner` / `winnerCui` | Winning supplier name + fiscal number (awarded contracts). |
| `sourceUrl` | Link to the notice on e-licitatie.ro. |
| `scrapedAt` | Extraction timestamp (UTC). |

### Use cases

- **Bid pipeline**: keyword + CPV + dateFrom for this month → a fresh list of
  relevant tenders with deadlines every morning.
- **Award monitoring**: `mode: awarded` + your CPV → track winners and prices
  for competitive intelligence.
- **Research**: pull 500 notices per run into a dataset for analysis.

### Pricing

Pay per event — you only pay for what you extract:

- **apify-actor-start** — one-time charge per run.
- **result** — per notice returned (default primary event).

No monthly fee, no hidden costs.

### Limitations

- The platform caps a single unauthenticated search at ~3,000 results
  (`searchTooLong`); for wider windows, narrow by date range or CPV.
- Titles/descriptions are as published by authorities — Romanian diacritics
  vary (some notices use ASCII transliteration).
- Awarded-value fields are `0.0` when the authority did not publish a value.
- The API is a live government service; occasional 5xx retries are handled
  automatically with backoff.
- Hard API failures are loud, not silent: if e-licitatie.ro answers 403 (the
  anti-hotlink "Referrer cannot be null"), 400, or an empty/invalid response,
  the run FAILS with a clear error instead of exiting successfully with zero
  items. A zero-item run therefore means a genuinely empty search, never a
  swallowed error.

# Actor input Schema

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

Free-text search in the contract title / object (Romanian, e.g. infrastructura, drumuri, medicamente). Leave empty to browse the latest notices.

## `cpvCode` (type: `string`):

CPV code or code prefix (e.g. 45233140-2 or 45233100). Filters notices whose main CPV matches.

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

Only notices published on or after this date (YYYY-MM-DD).

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

Only notices published on or before this date (YYYY-MM-DD).

## `authority` (type: `string`):

Contracting authority name filter (partial match, Romanian, e.g. Primaria, Consiliul Local).

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

tenders = participation notices (open procurement). awarded = contract award notices (won contracts with winners). both = both types.

## `fetchDetails` (type: `boolean`):

Fetch the full notice page per result (description, authority contact details, and winners for awarded contracts). Slower but much richer output.

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

Maximum number of notices to extract.

## Actor input object example

```json
{
  "keyword": "infrastructura",
  "mode": "tenders",
  "fetchDetails": true,
  "maxItems": 50
}
```

# Actor output Schema

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

No description

## `contractId` (type: `string`):

No description

## `noticeNo` (type: `string`):

No description

## `noticeType` (type: `string`):

No description

## `title` (type: `string`):

No description

## `description` (type: `string`):

No description

## `authority` (type: `string`):

No description

## `authorityCui` (type: `string`):

No description

## `cpvCode` (type: `string`):

No description

## `acquisitionType` (type: `string`):

No description

## `procedureType` (type: `string`):

No description

## `contractType` (type: `string`):

No description

## `estimatedValueRon` (type: `string`):

No description

## `contractValueRon` (type: `string`):

No description

## `publicationDate` (type: `string`):

No description

## `deadline` (type: `string`):

No description

## `awardDate` (type: `string`):

No description

## `status` (type: `string`):

No description

## `winner` (type: `string`):

No description

## `winnerCui` (type: `string`):

No description

## `sourceUrl` (type: `string`):

No description

## `scrapedAt` (type: `string`):

No description

# 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 = {
    "keyword": "infrastructura",
    "cpvCode": "",
    "dateFrom": "",
    "dateTo": "",
    "authority": "",
    "mode": "tenders"
};

// Run the Actor and wait for it to finish
const run = await client.actor("darknezz/ro-public-contracts-scraper").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 = {
    "keyword": "infrastructura",
    "cpvCode": "",
    "dateFrom": "",
    "dateTo": "",
    "authority": "",
    "mode": "tenders",
}

# Run the Actor and wait for it to finish
run = client.actor("darknezz/ro-public-contracts-scraper").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 '{
  "keyword": "infrastructura",
  "cpvCode": "",
  "dateFrom": "",
  "dateTo": "",
  "authority": "",
  "mode": "tenders"
}' |
apify call darknezz/ro-public-contracts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,darknezz/ro-public-contracts-scraper"
        }
    }
}

```

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/0cHCWyvVq1ew2McNJ/builds/mGWJD1vqKEPhIuWzW/openapi.json
