# Turkey Public Tender Tracker (EKAP) (`afkdigital/turkey-public-tender-tracker`) Actor

Filter official Turkish public tender notices by keyword, sector text, province, date, and procurement type.

- **URL**: https://apify.com/afkdigital/turkey-public-tender-tracker.md
- **Developed by:** [AFK Digital](https://apify.com/afkdigital) (community)
- **Stats:** 3 total users, 1 monthly users, 94.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 tender notice 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?

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

## Turkey Public Tender Tracker (EKAP)

**Find the Turkish public tenders that match your business.** Search the official EKAP Public Procurement Bulletin by publication date, procurement type, keywords, sector phrases, and province or region. Results include tender ID (İKN), title, contracting institution, official category, publication date, tender/deadline date when present, and a link to the official EKAP bulletin archive.

Türkiye'de faaliyet gösteren tedarikçi ve teklif ekipleri için: seçtiğiniz tarihlerde, sektörünüzle ve bölgenizle eşleşen kamu ihalelerini tek bir Apify Dataset'inde alın.

### What it answers

> “Which Turkish public tender notices published on these dates match my products or services and the regions I serve, and what is each tender's official ID and submission date?”

This Actor reads one source: the publicly accessible EKAP Public Procurement Bulletin archive. It is independent of AFK's e-commerce Price & Stock Actor.

### Input

| Field | Type | Behavior |
|---|---|---|
| `dateFrom`, `dateTo` | Date | Inclusive publication dates. Defaults to yesterday through today in Europe/Istanbul. Maximum span: 7 calendar days. |
| `keywords` | Text list | Every entered term must occur in the notice text. Case-insensitive. |
| `sectors` | Text list | Any phrase must occur in the notice text. Supply the sector terms you use, such as `software`, `medical supplies`, or `construction`; the Actor does not invent sector labels. |
| `regions` | Text list | Any phrase must occur in the published authority address or delivery location. |
| `procurementTypes` | List | Official categories: `MAL`, `YAPIM`, `HIZMET`, `DANISMANLIK`. |
| `maxResults` | Integer | 1–500; default 100. |

Example:

```json
{
  "dateFrom": "2026-10-05",
  "dateTo": "2026-10-05",
  "keywords": ["akaryakıt"],
  "sectors": ["akaryakıt"],
  "regions": ["Muğla"],
  "procurementTypes": ["MAL"],
  "maxResults": 20
}
```

### Output

One row per unique İKN:

```json
{
  "tenderId": "2026/1809334",
  "title": "Akaryakıt Ürünleri Mal Alımı",
  "institution": "Marmaris Belediye Başkanlığı Makine İkmal, Bakım ve Onarım Müdürlüğü",
  "category": "MAL",
  "publicationDate": "2026-10-05",
  "applicationDeadline": "2026-11-05T10:00:00+03:00",
  "officialUrl": "https://ekap.kik.gov.tr/ekap/ilan/bultenindirme.aspx"
}
```

Missing title, institution, or deadline values remain null. The official link opens EKAP's bulletin archive; use the İKN to locate the individual notice there. It is not an invented deep link. The `SUMMARY` key-value record reports source requests, bytes downloaded, elapsed/CPU time, parsed/returned counts, and any source errors. A partial source failure is explicitly flagged.

### Pricing

Pay per event:

- `search`: **$0.010** for a completed search with no source errors.
- `notice`: **$0.002** for each unique tender row returned.

A 20-row run costs $0.05 in event charges; a 100-row run costs at most $0.21. The first Apify-hosted benchmark completed in 32 seconds, used 0.0361 compute units and about 97 MB peak memory, and incurred **$0.007** in platform usage. At the measured cost, a 20-row run would leave about $0.033 after Apify's 20% revenue share and platform usage, before taxes or other account-level costs. Actual compute cost can vary by run size and runtime.

### Source use and limits

- Source: [EKAP Public Procurement Bulletin archive](https://ekap.kik.gov.tr/ekap/ilan/bultenindirme.aspx), maintained by Türkiye's Public Procurement Authority (Kamu İhale Kurumu).
- The Actor reads public bulletin ZIP/PDF files with a low request volume, extracts limited notice facts, and links users back to EKAP. It does not store or redistribute the source documents, access logged-in records, submit bids, or bypass access controls.
- The source pages establish public access to bulletin PDFs, but we did not find an explicit open-data/reuse license for the bulletin archive. This Actor provides factual fields with source attribution; commercial republication of the source documents is outside its scope. Stop use if the authority's current terms disallow automated retrieval or reuse.
- The archive may be delayed, unavailable, or updated. The Actor marks partial runs and retries transient connection resets up to three times.
- Category and sector phrase filters use source text. Sector phrases are keyword matching, not legal or CPV classification.
- Region phrases match only published institution/delivery text; they are not geocoded.
- `applicationDeadline` is the date/time printed in the notice. It may refer to the tender/offer opening date as labeled by the source, and can be absent. Always verify deadlines and notice changes at EKAP before bidding.
- The `officialUrl` points to the official bulletin archive page, not a unique per-notice detail URL.

### Local development

Python 3.12+:

```bash
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
python -m unittest discover -s tests -v
```

Build and run with Apify CLI:

```bash
apify login
apify run
apify push
```

The event definitions are documented in `.actor/pay_per_event.json`. Enable pay-per-event pricing in Apify Console with `search` ($0.010 per successful search) and `notice` ($0.002 per returned row); set `notice` as the primary event. The Store listing should explain the source, filters, output, cost example, and source-use limits.

### Attribution

Not affiliated with or endorsed by the Kamu İhale Kurumu. Source content and official records remain with EKAP/KİK.

# Actor input Schema

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

Inclusive. Defaults to today in Turkey.

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

Inclusive. Defaults to today in Turkey.

## `keywords` (type: `array`):

All entered keywords must occur in the notice text. Leave empty for no keyword filter.

## `sectors` (type: `array`):

Match any phrase in the official notice text, for example software, medical supplies, construction.

## `regions` (type: `array`):

Match any phrase in the institution address or delivery location.

## `procurementTypes` (type: `array`):

Official bulletin type codes: goods, works, services, and consultancy.

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

Hard output cap for this run.

## Actor input object example

```json
{
  "procurementTypes": [
    "MAL"
  ],
  "maxResults": 100
}
```

# Actor output Schema

## `tenders` (type: `string`):

No description

## `summary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("afkdigital/turkey-public-tender-tracker").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("afkdigital/turkey-public-tender-tracker").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 '{}' |
apify call afkdigital/turkey-public-tender-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afkdigital/turkey-public-tender-tracker"
        }
    }
}
```

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/kQdITcCCXFKKhrw3R/builds/msR6oWZ7ObPpc5tod/openapi.json
