# Baltic Procurement: Latvia, Lithuania & Estonia Tenders (`ayuki/baltic-public-procurement`) Actor

Unofficial Latvia, Lithuania and Estonia public procurement tenders and awards. Search IUB, Riigihanked (RHR) and TED open data by CPV and date. Export one schema with per-record licensing and attribution.

- **URL**: https://apify.com/ayuki/baltic-public-procurement.md
- **Developed by:** [LV Data Tools](https://apify.com/ayuki) (community)
- **Categories:** Lead generation, Open source, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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

## Baltic Public Procurement: Latvia, Lithuania & Estonia Tenders and Awards

Find **Latvia, Lithuania and Estonia tenders, public procurement contract notices and contract awards** in one normalised dataset. This Actor combines **IUB** Latvia open data, Estonia's **Riigihanked / Riigihangete register (RHR)** open-data API and **Tenders Electronic Daily (TED)**. Filter by country, publication date and **CPV codes** for construction, IT, supplies and services.

Use it for tender monitoring, bid planning, procurement analytics, sales opportunity research and public-spending analysis. Export complete records to JSON, CSV or Excel, or connect your Apify dataset to Make, Zapier, n8n or an AI agent.

> **Unofficial tool.** It is not affiliated with or endorsed by IUB, Riigi Tugiteenuste Keskus, the Publications Office of the EU or TED. It reads published open data only. No TED or EU logo is used.

### What data you get

All sources use the same fields. Missing published values are `null`; code lists are arrays.

| Field | Meaning |
|---|---|
| `country` | Requested buyer country: `LV`, `LT` or `EE` |
| `source` | IUB, RHR open data or TED |
| `noticeType`, `noticeId` | `contract_notice` or `contract_award`, and source notice identifier |
| `buyer`, `buyerId` | Contracting organisation and its public identifier; recognised natural persons and sole traders are withheld |
| `title`, `description` | Procurement subject in the source language; descriptions are scrubbed for IUB/RHR and withheld for TED |
| `cpv`, `nuts` | Eight-digit CPV codes and NUTS region codes |
| `estimatedValue`, `currency` | Published estimated or awarded value; awards can fall back to an estimate when no award total is published |
| `procedure` | Published procedure type |
| `deadline`, `publicationDate` | Earliest lot submission deadline and ISO publication date |
| `status` | `open`, `closed`, `awarded` or `unknown` |
| `url` | Link to the notice or procurement documents |
| `licence`, `licenceUrl`, `attribution` | Source licence, terms URL, source credit and modification statement for **every record** |

The dataset includes a tender overview table and an all-fields view. Both preserve the licensing fields when exported. Joint TED buyers are assigned the first requested country present in the notice's buyer-country list; notices without a requested buyer country are dropped. The displayed TED buyer name is the primary organisation and may be one of several joint buyers.

### Sources and coverage

| Country | Source | Coverage |
|---|---|---|
| Latvia | IUB open data, official daily JSON from `open.iub.gov.lv` | Contract notices and awards published in national open data, including EU notices |
| Estonia | Riigihanked / Riigihangete register, official monthly XML | Contract notices and awards from the RHR open-data API |
| Lithuania | TED Search API | Notices published in TED, mainly above EU thresholds |

Lithuanian below-threshold national coverage is not included. `tedCoverage: "all"` adds TED for Latvia and can duplicate IUB notices; cross-source duplicates are retained with their separate source and licence. **Estonian records are always obtained exclusively through `https://riigihanked.riik.ee/rhr/api/public/v1/opendata/...`, never by HTML scraping or a TED fallback**, and keep CC BY-SA 3.0. Source availability and publication delays can affect coverage.

### Input and examples

| Input | Default | Behaviour |
|---|---|---|
| `countries` | `["LV", "LT", "EE"]` | Select Latvia, Lithuania and/or Estonia |
| `noticeType` | `"open"` | `open` = contract notices; `awards` = contract awards; `both` = both categories |
| `daysBack` | `7` | Inclusive publication window ending today in UTC; 1–366 days, including all intersecting months |
| `maxItems` | `100` | Total output cap, interleaved across sources; `0` removes the item cap |
| `cpvCodes` | `[]` | CPV prefixes such as `45` (construction), `30` (office equipment) or `72` (IT) |
| `tedCoverage` | `"lt_only"` | TED for selected Lithuania; `all` adds selected Latvia. Estonia stays RHR-only |
| `tedMaxPages` | `150` | TED pagination safety limit, 1–1000 pages; up to 250 notices per page |
| `excludeFreeText` | `true` | Set all descriptions to `null` (default). Set `false` for scrubbed IUB/RHR descriptions; TED descriptions are always withheld |

`open` selects contract notices by publication date. Some have expired or missing deadlines; use `status` and the source notice to assess whether bids are still accepted. CPV filters match any published main or additional code. Padded codes such as `72000000` mean the hierarchy prefix `72`; short division prefixes such as `30` keep their trailing zero. Multiple CPV filters are combined with OR.

Monitor recently published Baltic tenders:

```json
{
  "countries": ["LV", "LT", "EE"],
  "noticeType": "open",
  "daysBack": 7,
  "maxItems": 100
}
```

Find construction awards across all three countries:

```json
{
  "countries": ["LV", "LT", "EE"],
  "noticeType": "awards",
  "cpvCodes": ["45"],
  "tedCoverage": "all",
  "daysBack": 7,
  "maxItems": 100
}
```

TED uses server-side wildcard CPV filtering, for example `classification-cpv = 45*`, supported by the [official TED search documentation](https://ted.europa.eu/en/help/search-browse). Token-based iteration avoids the 15,000-notice ceiling of page-number queries; per-request page and field limits still apply. See [TED Search API modes and limits](https://docs.ted.europa.eu/ODS/latest/reuse/search-api.html).

### Run statistics and reliability

The `RUN_STATS` key-value-store record contains the total, UTC date range, runtime, selected countries, output-cap flag and `sources.iub`, `sources.rhr`, `sources.ted`. Each source reports status (`ok`, `partial`, `error` or `disabled`), fetched and output counts, HTTP requests, retries, empty responses, malformed records, dropped countries, duplicates, TED pages, limit flags and privacy-safe errors. Malformed-record examples are limited to five per source; `malformedRecords` counts all skipped records.

All source requests have connection and total timeouts and up to four attempts with exponential backoff, jitter and bounded `Retry-After` handling for 429/5xx and network errors. Malformed responses are retried; malformed individual records are skipped. Missing daily files and empty monthly files do not stop a run. A failed source does not stop other sources, and later dates/months can still be processed. An exhausted request or TED page limit is recorded explicitly, so a successful Actor exit can still contain partial coverage.

### Example output

```json
{
  "country": "EE",
  "source": "EE Riigihangete register open data",
  "noticeType": "contract_notice",
  "noticeId": "00000000-0000-0000-0000-000000000001",
  "buyer": "Example contracting authority",
  "buyerId": null,
  "title": "Example supply procurement",
  "description": null,
  "cpv": ["31700000"],
  "nuts": ["EE001"],
  "estimatedValue": 350000,
  "currency": "EUR",
  "procedure": "open",
  "deadline": "2026-11-02 13:00",
  "publicationDate": "2026-09-30",
  "status": "open",
  "url": null,
  "licence": "CC BY-SA 3.0 (as declared on andmed.eesti.ee)",
  "licenceUrl": "https://creativecommons.org/licenses/by-sa/3.0/",
  "attribution": "Source: Riigi Tugiteenuste Keskus, Riigihangete register (riigihanked.riik.ee open data), CC BY-SA 3.0. Modified: fields extracted and normalised by LV Data Tools; contact persons removed. This record may be freely redistributed under CC BY-SA 3.0."
}
```

### Licensing

Every record carries its own `licence`, `licenceUrl` and `attribution` fields. Keep them when you reuse the data.

- **Latvia (IUB):** CC0 1.0 (public domain dedication) as published on data.gov.lv.
- **Estonia (Riigihangete register / RHR):** **CC BY-SA 3.0 (as declared on andmed.eesti.ee)**, © Riigi Tugiteenuste Keskus. The records are **Modified**: fields are extracted and normalised, and contact persons are removed. Redistribution of Estonian records or derivatives must credit the source, indicate changes and stay under CC BY-SA 3.0 (or a compatible licence). **You are free to redistribute the Estonian records under CC BY-SA 3.0. Nothing in this Actor or its terms restricts that right.** See the [CC BY-SA 3.0 terms](https://creativecommons.org/licenses/by-sa/3.0/); no additional restrictions are imposed.
- **TED:** procurement notices are reused under the European Commission's reuse policy (Decision 2011/833/EU), which permits commercial and non-commercial reuse unless otherwise noted. Source: Publications Office of the EU, ted.europa.eu. Records are modified (normalised and minimised). Website editorial content has separate CC BY 4.0 terms; third-party rights and identifiable individuals can require separate clearance. No TED or EU logo is used. See the [TED legal notice](https://ted.europa.eu/en/legal-notice).
- The Actor's price pays for the processing service, not for a licence to the data.
- The Actor's code is © LV Data Tools. Code/service terms do not limit the source data's reuse rights.

### Personal data

Procurement notices may contain contact-person names, phone numbers and e-mails. **This Actor never outputs contact-person `Name`, `Telephone`, `ElectronicMail` or contact objects.** It builds records from an allowlist of procurement fields. Known contacts from IUB JSON and RHR XML are used only in memory to remove copies from output text; email addresses, phone patterns and labelled contact details are also removed. TED requests omit contact fields and descriptions. Recognised natural persons and sole traders are redacted. Logs and `RUN_STATS` contain no raw records, response bodies or contact values.

The retained organisation names, identifiers and subject titles are intended to describe procurement, but identifying an arbitrary natural-person name in unstructured text cannot be guaranteed. `excludeFreeText` is on by default and omits descriptions for additional minimisation. Estonian buyers whose registry code starts with 9 (FIE / sole traders) are withheld even when the name lacks the "FIE" token. Public availability and an open-data licence do not remove GDPR obligations.

**Roles:** the publisher (LV Data Tools) is controller for the Actor's own source collection and minimisation, and acts as processor for each user's run output under §5.2 of the Apify Standard Actor Contract, while the user is controller of that output and its reuse.

### Privacy notice

Controller: **Artyom Kutnevskiy (trading as LV Data Tools), contact lvdatatools@gmail.com**. Version 0.2, 2026-10-13.

- **Data concerned:** public procurement notices and awards for Latvia, Lithuania and Estonia. Output concerns procurement subjects, contracting organisations, public identifiers, CPV/NUTS codes, values and dates. Source payloads may incidentally contain contact persons, sole traders, natural-person winners or personal details in text.
- **Minimisation:** contact-person `Name`, `Telephone`, `ElectronicMail` and contact objects are never output. The Actor uses an allowlist of procurement fields, omits winner records and withholds buyers marked as natural persons (IUB) and recognised sole traders/farms. IUB/RHR contact values are used only transiently in memory to redact repeated values from retained text. Emails, international/Baltic phone patterns, labelled contact details and simple name patterns are scrubbed. TED contact fields and descriptions are not requested; its `description` is null. `excludeFreeText` (on by default) omits all descriptions. Estonian buyers with FIE registry codes (starting with 9) are withheld. Arbitrary personal names in titles, descriptions or organisation fields cannot all be recognised by patterns; any identified personal contact data must be removed.
- **Sources:** Iepirkumu uzraudzības birojs, Latvia (`open.iub.gov.lv`, daily JSON, CC0 1.0); Riigi Tugiteenuste Keskus, Estonia (Riigihanked / Riigihangete register, **only** `https://riigihanked.riik.ee/rhr/api/public/v1/opendata/...`, monthly XML, **CC BY-SA 3.0 (as declared on andmed.eesti.ee)**); Publications Office of the EU, TED Search API (`api.ted.europa.eu`, for Lithuania and optionally Latvia). No Estonian HTML is accessed and there is no TED fallback for Estonia.
- **Source licensing:** every record includes its licence, terms URL and attribution. EE records state **Modified** and may be freely redistributed under CC BY-SA 3.0, with credit, change indication and applicable ShareAlike terms. **Nothing in the Actor or its service terms restricts EE redistribution.** TED procurement notices follow Commission Decision 2011/833/EU and the [TED legal notice](https://ted.europa.eu/en/legal-notice); third-party/personal rights may apply separately. The Actor is unofficial and uses no TED/EU logo. An open-data licence does not waive privacy obligations.
- **Roles:** the publisher (LV Data Tools) is controller for the Actor's own source collection and minimisation, and acts as processor for each user's run output under §5.2 of the Apify Standard Actor Contract, while the user is controller of that output and its reuse.
- **Purpose:** structured access to public tenders and awards for businesses, suppliers, analysts and researchers, including bid monitoring and procurement market research. No profiling of people, personal-contact enrichment or automated decision-making about individuals is performed.
- **Legal basis:** Art. 6(1)(f) GDPR, the stated legitimate interest, with minimisation and balancing described in the legitimate-interest assessment (available on request from lvdatatools@gmail.com). Users must establish the basis for their own reuse.
- **Recipients:** the user running the Actor and recipients they choose when exporting or sharing their dataset. Apify Technologies s.r.o. provides the hosting platform; controller/processor roles depend on the applicable service arrangements. Datasets are not automatically sent to other parties by this Actor.
- **Retention:** LV Data Tools keeps no separate copy of output. Source responses are processed in memory. Output datasets and `RUN_STATS` belong to the user's run and follow the user's Apify storage/retention settings. Diagnostics contain counters and privacy-safe error summaries, not raw notice/contact values. Users act as independent controllers of their datasets and downstream reuse.
- **Transfers outside the EEA:** hosting may involve transfers depending on Apify's infrastructure and the user's arrangements. Consult [Apify's privacy policy](https://apify.com/privacy-policy) and applicable data-processing terms for current details and safeguards.
- **Rights:** access, rectification, erasure, restriction, objection under Art. 21 and complaint to a supervisory authority, as applicable. Latvia: Datu valsts inspekcija ([dvi.gov.lv](https://www.dvi.gov.lv/)); Estonia: Andmekaitse Inspektsioon ([aki.ee](https://www.aki.ee/)); Lithuania: Valstybinė duomenų apsaugos inspekcija ([vdai.lrv.lt](https://vdai.lrv.lt/)). Requests concerning the Actor go to lvdatatools@gmail.com; for a user's retained/exported dataset, contact that user as well. Requests are reviewed individually. This version has no automatic exclusion list; corrections, exclusion in a release or removal from a controlled dataset must be handled as applicable.
- **Individual notification / Art. 14(5)(b) assessment (2026-10-14):** the Actor retains no contact data and no separate copy of output; data subjects appear only incidentally (e.g. sole-trader names, names in titles) in notices that public authorities already published. The publisher holds no contact details for them, and identifying and contacting them would require collecting the very personal data the Actor is designed to discard, which would increase intrusion. Individual notification is therefore impossible or would involve disproportionate effort. Safeguards instead: this public notice (this README section), contact/winner exclusion, sole-trader redaction (incl. Estonian FIE registry codes), descriptions omitted by default, and individual handling of objections.

### FAQ

**Is this official?** No. It is an independent tool built on published open data.

**Can I get Lithuanian below-threshold tenders?** National below-threshold coverage is not included; only notices available in TED are returned.

**How fresh is it?** The Actor reads source files/API responses during each run. IUB daily files and RHR monthly XML can lag the current date, and TED publication follows its working-day schedule. Check `RUN_STATS` and the source notice.

# Actor input Schema

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

LV = Latvia (IUB), EE = Estonia (Riigihanked/RHR open-data API only, CC BY-SA 3.0), LT = Lithuania (TED, mainly above EU thresholds).

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

Contract notices, contract awards, or both within the publication window. Contract notices can have open, closed or unknown deadlines; check status before bidding.

## `daysBack` (type: `integer`):

Publication window in days, ending today (UTC).

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

Maximum records in total, interleaved across sources. 0 removes the item cap; TED still has a configurable page safety limit.

## `cpvCodes` (type: `array`):

Optional CPV prefixes, e.g. 45 (construction), 30 (office equipment), or 72000000 (IT services). Padded codes use their hierarchy prefix; division prefixes keep trailing zeros. TED filters run on the server.

## `tedCoverage` (type: `string`):

TED always covers selected Lithuania. All adds selected Latvia. Estonia always uses only the RHR open-data API, preserving CC BY-SA 3.0 and free redistribution.

## `tedMaxPages` (type: `integer`):

Safety limit for token-based TED pagination (up to 250 notices per page). Reaching it is reported in RUN_STATS as potentially incomplete coverage.

## `excludeFreeText` (type: `boolean`):

On by default: description is null for maximum minimisation (free text can contain personal names). Turn off to get scrubbed IUB/RHR descriptions. Contact fields are always excluded. TED descriptions are always withheld.

## Actor input object example

```json
{
  "countries": [
    "LV",
    "LT",
    "EE"
  ],
  "noticeType": "open",
  "daysBack": 7,
  "maxItems": 100,
  "cpvCodes": [],
  "tedCoverage": "lt_only",
  "tedMaxPages": 150,
  "excludeFreeText": true
}
```

# Actor output Schema

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

No description

## `stats` (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 = {
    "countries": [
        "LV",
        "LT",
        "EE"
    ],
    "daysBack": 7,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("ayuki/baltic-public-procurement").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 = {
    "countries": [
        "LV",
        "LT",
        "EE",
    ],
    "daysBack": 7,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("ayuki/baltic-public-procurement").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 '{
  "countries": [
    "LV",
    "LT",
    "EE"
  ],
  "daysBack": 7,
  "maxItems": 100
}' |
apify call ayuki/baltic-public-procurement --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ayuki/baltic-public-procurement"
        }
    }
}
```

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/i3OzaTZuYRWlqsOTj/builds/3oNVroqEoXNrmIwAJ/openapi.json
