# Kazakhstan Public Procurement Tenders (goszakup.gov.kz) (`yadroo/goszakup-kz-tenders`) Actor

State procurement announcements and lots from Kazakhstan's official goszakup.gov.kz portal: one row per announcement or lot with number, name, amount in tenge, procurement method, status and application dates. Filter by keyword, customer, method, status, amount or financial year.

- **URL**: https://apify.com/yadroo/goszakup-kz-tenders.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** Business, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 tender row returneds

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

## Kazakhstan Public Procurement Tenders (goszakup.gov.kz)

State procurement announcements and lots from Kazakhstan's official goszakup.gov.kz portal: one row per announcement or lot with number, name, amount in tenge, procurement method, status and application dates. Filter by keyword, customer, method, status, amount or financial year.

The public search of the Republic of Kazakhstan's state procurement portal, turned into clean rows. Pick **announcements** to see which tenders were published — amount in tenge, procurement method, status, the window in which applications are accepted — or **lots** to see what is actually being bought, with the lot name, its quantity and its own amount. Search by Russian or Kazakh keyword, by buying organisation, by procurement method, status, amount band or financial year, and switch on the customer details to get the buyer's full name, its BIN and its registered address. No API key, no login, no proxy and no browser: the portal publishes these pages for everyone.

> **Need it tailored to your workflow?** Missing a field, a filter, another source or a different output format? [Open an issue](https://apify.com/yadroo/goszakup-kz-tenders/issues) and describe what you need — we read every request and adapt the actor.

### Use cases

- **Find work to bid on**: a contractor or supplier searches `ремонт`, `строительство` or `компьютер`, takes the rows whose status is still open for applications, and reads the deadline out of `applicationEndDate`.
- **Watch one buyer**: set `customer` to a ministry, a city administration or a state company and run it on a schedule with `onlyNew` — each run writes only the announcements that appeared since the last one.
- **Alert on big money**: `amountFrom: 500000000` plus `sinceDays: 1` on an hourly schedule gives journalists and compliance teams the half-billion-tenge purchases the day they are published.
- **Study a market**: `status: ["Завершено"]` with a `financialYear` and a `method` is the base table for "how much was spent on what, and how was it awarded".
- **Vet a counterparty before a deal**: `includeCustomer: true` adds the buyer's registered name, BIN and address, so the rows join straight onto your own supplier or tax data.
- **Answer questions in an agent**: one call per question ("any open tenders for school furniture in Kazakhstan?") — the actor takes the keyword as typed and returns rows, not HTML.

### Input

Nothing is required: with no input at all the run returns the newest announcements.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `mode` | string (enum) | `announcements` | `announcements` (one row per announcement) or `lots` (one row per lot). Strict: any other value is refused by the platform before the run starts. |
| `query` | string | empty | Keyword searched by the portal inside the announcement name (and the lot name in `lots` mode). Sent exactly as typed, so Russian and Kazakh words work and part of a word matches longer forms; Latin transliteration does not match. Empty = no name filter. |
| `customer` | string | empty | Substring of the buying organisation's registered name (`школа`, `больница`, `акимат`, `КазМунайГаз`). Sent as typed. |
| `announcementNumber` | string | empty | One announcement by its number, with or without the lot suffix: `17911453` or `17911453-1`. Narrows the search to that single announcement. |
| `method` | string\[] | empty | Procurement methods, one per line, as the portal prints them — see [Procurement methods](#procurement-methods). Case, extra spaces, the Kazakh spelling and the portal's numeric id are accepted; anything else stops the run with the closest names. Empty = every method. |
| `status` | string\[] | empty | Announcement statuses (or **lot** statuses in `lots` mode) — see [Statuses](#announcement-statuses). Same forgiving matching as `method`. Empty = every status. |
| `amountFrom` | integer | empty | Keep only rows whose published amount is at least this many tenge. Applied by the portal. |
| `amountTo` | integer | empty | Upper bound of the published amount in tenge. Applied by the portal. |
| `financialYear` | integer | empty | Budget year of the purchase, 2015–2030. Empty = every year the portal holds, newest first. |
| `sinceDays` | integer | empty | 1–365. Keep only rows whose application window starts within this many days back from today (UTC), and stop paging once a whole page is older. `announcements` mode only — the lot registry prints no dates, and the run says so in its status. |
| `onlyNew` | boolean | `false` | Remember the announcement or lot numbers written, and on the next run of the same actor or task write only numbers not written before. The memory is kept per filter set, so two schedules watching two customers never mix. |
| `includeCustomer` | boolean | `false` | Open the announcement page of every row as well, to add `customerName`, `customerBin`, `customerAddress`, `subjectType`, `purchaseType` and `lotCount`. One extra request per row at five seconds each — use it with a small row cap. Contact people printed on those pages are never written out. |
| `maxItems` | integer | `50` | 1–1000. Hard cap on the rows this run writes, and so on what it costs. |
| `fields` | string\[] | all | Keep only these columns, **in this order**. `mode`, `announcementNumber`, `announcementName`, `amountTenge`, `status`, `url` and `fetchedAt` are always kept — they come first unless you list them, and a name you do list stays where you put it. A name that is not a column is reported in the run status. |

### Reference

All dictionaries below are the portal's own select lists, read from `old.goszakup.gov.kz` on **2026-11-04**. You can type the Russian name, the Kazakh name of a method, a different case or spacing, or the numeric id.

#### Procurement methods

| Id | Name on the portal |
|---|---|
| 2 | Открытый конкурс |
| 3 | Запрос ценовых предложений |
| 6 | Из одного источника по несостоявшимся закупкам |
| 7 | Аукцион (до 2022) |
| 22 | Конкурс с применением двухэтапных процедур |
| 32 | Конкурс с предварительным квалификационным отбором |
| 50 | Закупка жилища |
| 52 | Закупка по государственному социальному заказу |
| 77 | Аукцион (с 2022) |
| 78 | Аукцион |
| 120 | Конкурс по приобретению услуг по организации питания воспитанников и обучающихся |
| 121 | Конкурс по приобретению товаров, связанных с обеспечением питания воспитанников и обучающихся |
| 124 | Тендер |
| 125 | Из одного источника по несостоявшимся закупкам не ГЗ |
| 126 | Запрос ценовых предложений (не ГЗ new) |
| 128 | Конкурс с применением специального порядка |
| 130 | Государственные закупки с применением особого порядка |
| 132 | Первый этап конкурса с использованием рамочного соглашения |
| 133 | Второй этап конкурса с использованием рамочного соглашения |
| 177 | Аукцион (не ГЗ) с 2022 г |
| 178 | Аукцион (не ГЗ) |
| 188 | Конкурс с использованием рейтингово-балльной системы |
| 190 | Тендер с применением особого порядка |
| 200 | Тендер с использованием рейтингово-балльной системы |
| 201 | Конкурс по строительству «под ключ» |
| 202 | Тендер по строительству «под ключ» |

The Kazakh spelling of each method is accepted as well (`Ашық конкурс` = 2, `Бағалы ұсыныныстарға сұраным` = 3, …). Two exceptions: ids 125 and 126 have no Kazakh form of their own, because the portal prints for them the same Kazakh name as for 6 and 3 — use their Russian name or their id.

#### Announcement statuses

Used in `announcements` mode.

| Id | Status | | Id | Status |
|---|---|---|---|---|
| 190 | Изменена документация | | 410 | Отказ от закупки |
| 210 | Опубликовано | | 420 | Приостановлено |
| 220 | Опубликовано (прием заявок) | | 430 | Отменено |
| 230 | Опубликовано (дополнение заявок) | | 440 | На обжаловании |
| 240 | Опубликовано (прием ценовых предложений) | | 444 | Ожидание камерального контроля |
| 250 | Рассмотрение заявок | | 445 | Ожидание проведения контроля качества |
| 260 | Рассмотрение дополнений заявок | | 450 | Отправлено на контроль качества |
| 270 | Заполнение условных скидок | | 460 | Пройдено контроль качества |
| 280 | Опубликовано (ожидание проведения аукциона) | | 510 | Пересмотр итогов |
| 310 | Формирование протокола преддопуска | | 540 | Принятие решение об исполнении уведомления |
| 320 | Формирование протокола допуска | | 550 | Принятие решение о пересмотре итогов |
| 325 | Формирование протокола промежуточных итогов | | 350 | Завершено |
| 330 | Формирование протокола итогов | | | |

For tenders still open for bids use `Опубликовано`, `Опубликовано (прием заявок)` and `Опубликовано (прием ценовых предложений)`; for finished purchases, `Завершено`.

#### Lot statuses

Used in `lots` mode — the lot registry keeps its own, shorter list, so `Завершено` is not a lot status.

| Id | Status | | Id | Status |
|---|---|---|---|---|
| 190 | Изменена документация | | 370 | Закупка не состоялась |
| 210 | Опубликован | | 410 | Отказ от лота |
| 220 | Опубликован (прием заявок) | | 420 | Приостановлен |
| 230 | Опубликован (дополнение заявок) | | 430 | Отменен |
| 240 | Опубликован (прием ценовых предложений) | | 440 | На обжаловании |
| 250 | Рассмотрение заявок | | 444 | Ожидание камерального контроля |
| 260 | Рассмотрение дополнений заявок | | 445 | Ожидание проведения контроля качества |
| 270 | Заполнение условных скидок | | 460 | Пройдено контроль качества |
| 280 | Опубликовано (ожидание проведения аукциона) | | 510 | Пересмотр итогов |
| 310 | Формирование протокола преддопуска | | 540 | Принятие решение об исполнении уведомления |
| 320 | Формирование протокола допуска | | 550 | Принятие решение о пересмотре итогов |
| 325 | Формирование протокола промежуточных итогов | | 360 | Закупка состоялась |
| 330 | Формирование протокола итогов | | | |

#### Financial years

2015–2030 are accepted; the portal's own list offers 2016–2027 today. A purchase planned for next year appears late in the current one, so the budget year is not always the year of publication.

### Examples

**What is the Kazakh state buying right now?**

```json
{ "mode": "announcements", "maxItems": 40 }
```

**Repair and construction work for a contractor**

```json
{ "mode": "announcements", "query": "ремонт", "maxItems": 30 }
```

**Open competitions of this budget year, for a bid writer**

```json
{ "mode": "announcements", "method": ["Открытый конкурс"], "financialYear": 2026, "maxItems": 25 }
```

**Purchases of half a billion tenge and more**

```json
{ "mode": "announcements", "amountFrom": 500000000, "financialYear": 2026, "maxItems": 25 }
```

**Lots a computer supplier can bid on**

```json
{ "mode": "lots", "query": "компьютер", "maxItems": 30 }
```

**Tenders of one buyer, with its BIN and address**

```json
{ "mode": "announcements", "customer": "школа", "includeCustomer": true, "maxItems": 15 }
```

**A daily watch list: only what appeared since the last run**

```json
{ "mode": "announcements", "query": "медикаменты", "sinceDays": 2, "onlyNew": true, "maxItems": 100 }
```

**One announcement by its number**

```json
{ "announcementNumber": "17911453-1" }
```

### Output

A real row from the cloud run `jBNBLaUICVTwIjDRO` (`customer: школа`, `includeCustomer: true`, 2026-11-04):

```json
{
  "mode": "announcements",
  "announcementNumber": "17911453-1",
  "announcementId": 17911453,
  "announcementName": "Услуги по страхованию гражданско-правовой ответственности владельцев автомобильного транспорта",
  "method": "Запрос ценовых предложений",
  "status": "Опубликовано",
  "amountTenge": 51724.13,
  "currency": "KZT",
  "applicationStartDate": "2026-11-05",
  "applicationEndDate": "2026-11-09",
  "financialYear": null,
  "url": "https://old.goszakup.gov.kz/ru/announce/index/17911453",
  "announcementUrl": "https://old.goszakup.gov.kz/ru/announce/index/17911453",
  "fetchedAt": "2026-11-04T22:46:01.908Z",
  "customerName": "Коммунальное государственное учреждение \"Средняя школа №131 имени Талгат Козыбаева\" отдела образования по Сырдарьинскому району Управления образования Кызылординской области\"",
  "customerBin": "981140001988",
  "customerAddress": "434830100, 120600, Казахстан, г. Теренозек, ул. КАСЫМ БОДЕЕВ, д. 9, оф.",
  "subjectType": "Услуга",
  "purchaseType": "Первая закупка",
  "lotCount": 1
}
```

And one lot row, from run `SVPvEa4gVRHU20JR1` (`mode: lots`, `query: компьютер`):

```json
{
  "mode": "lots",
  "announcementNumber": "17910893-1",
  "announcementId": 17910893,
  "announcementName": "Приобретение компьютера (моноблок)",
  "method": "Запрос ценовых предложений",
  "status": "Опубликован",
  "amountTenge": 775862.07,
  "currency": "KZT",
  "financialYear": null,
  "lotNumber": "88037772-ЗЦП3",
  "lotId": 43814783,
  "lotName": "Компьютер",
  "lotDescription": null,
  "quantity": 1,
  "url": "https://old.goszakup.gov.kz/ru/subpriceoffer/index/17910893/43814783",
  "announcementUrl": "https://old.goszakup.gov.kz/ru/announce/index/17910893",
  "fetchedAt": "2026-11-04T22:46:01.461Z"
}
```

| Field | Type | Meaning |
|---|---|---|
| `mode` | string | `announcements` or `lots` — which list the row came from. Always written. |
| `announcementNumber` | string | Announcement number as the portal prints it, e.g. `17911454-1`. Always written. |
| `announcementId` | number | Numeric part of that number, the id used in the portal URLs. |
| `announcementName` | string | Name of the announcement, in the language it was filed in. Always written. |
| `method` | string | Procurement method, e.g. `Открытый конкурс`. |
| `status` | string | Status text of the announcement, or of the lot in `lots` mode. Always written. |
| `amountTenge` | number | Published amount in tenge: the announcement total, or the lot amount in `lots` mode. Always written. |
| `currency` | string | Always `KZT`. |
| `applicationStartDate` | string | `YYYY-MM-DD`, first day applications are accepted. `announcements` mode. |
| `applicationEndDate` | string | `YYYY-MM-DD`, last day applications are accepted. `announcements` mode. |
| `financialYear` | number | The budget year — filled when you pinned one with `financialYear`, otherwise `null` (the search pages do not print it). |
| `lotNumber` | string | Lot number, e.g. `88037772-ЗЦП3`. `lots` mode. |
| `lotId` | number | Numeric lot id used in the portal URL. `lots` mode. |
| `lotName` | string | What the lot buys, e.g. `Компьютер`. `lots` mode. |
| `lotDescription` | string | Longer lot description where the buyer filled one in, else `null`. `lots` mode. |
| `quantity` | number | Quantity of the lot. `lots` mode. |
| `customerName` | string | Registered name of the buying body. Only with `includeCustomer`. |
| `customerBin` | string | Its BIN (12-digit business identification number). Only with `includeCustomer`. |
| `customerAddress` | string | Its registered address as the portal prints it. Only with `includeCustomer`. |
| `subjectType` | string | `Товар`, `Услуга` or `Работа` — goods, a service or work. Only with `includeCustomer`. |
| `purchaseType` | string | `Первая закупка` or `Повторная закупка`. Only with `includeCustomer`. |
| `lotCount` | number | How many lots the announcement has. Only with `includeCustomer`. |
| `url` | string | Portal page of the row: the lot page in `lots` mode, the announcement page otherwise. Always written. |
| `announcementUrl` | string | Portal page of the announcement, in both modes. |
| `fetchedAt` | string | When the row was read, ISO 8601 UTC. Always written. |

Dataset views: **Announcements**, **Lots**, **Customers**.

Every run also writes a `SUMMARY` record into the run's key-value store: mode, pages read, how many matches the portal reported, rows dropped as already delivered or outside the date window, and the final status line.

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~goszakup-kz-tenders/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"announcements","query":"ремонт","maxItems":30}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/goszakup-kz-tenders').call({ mode: 'announcements', query: 'ремонт', maxItems: 30 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/goszakup-kz-tenders").call(run_input={"mode": "announcements", "query": "ремонт", "maxItems": 30})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the `yadroo/goszakup-kz-tenders` tool with the same JSON input.

Two things worth knowing when you automate it: `fields` decides the column order of every row, and `onlyNew` makes a schedule cheap — the memory is kept per filter set, so one task per customer or keyword each keep their own history.

### Pricing

Pay per event: **$0.001 per run start + $0.003 per dataset row**. The start event is charged on every run, including a run that finds nothing. Rows are charged as they are written, so you only pay for what the run actually delivered. Tier discounts apply to the row event (Bronze −10 %, Silver −20 %, Gold and above −30 %, i.e. $0.0021 per row); the start event is flat.

| Run | Rows | Cost |
|---|---|---|
| Default run: newest announcements for a keyword | 50 | $0.001 + 50 × $0.003 = **$0.151** |
| One buyer with customer details | 15 | $0.001 + 15 × $0.003 = **$0.046** |
| A supplier's lot sweep | 300 | $0.001 + 300 × $0.003 = **$0.901** |
| One announcement by number | 1 | $0.001 + 1 × $0.003 = **$0.004** |

A search that matches nothing writes no rows at all — no "not found" marker rows are produced — so such a run costs only the $0.001 start event and says in its status which filters matched nothing.

The run also respects the **Maximum cost per run** you set in the run options: when the budget is used up, the actor stops, keeps every row you paid for and ends with "Stopped at your spending limit: N rows delivered".

### Limits & FAQ

**How fast is it?** Measured in the Apify cloud on 2026-11-04 at 256 MB: a search without customer details is **one request per page of up to 100 rows** — 50 rows in 5 s, 40 rows in 5 s, and the largest allowed run of 1000 rows needs 10 requests, about a minute. With `includeCustomer: true` every row costs one extra page: **15 rows in 108 s**, roughly 8 rows per minute. Within the default 900-second run timeout that means the whole 1000-row cap for a plain search, but only about 150 rows with the customer details on.

**What pace does it keep?** The portal's `robots.txt` asks every crawler for five seconds between requests, and the actor keeps to exactly that — one request per 5 s, retries included, about 12 requests per minute. We never go faster to beat a deadline. No throttling, 429 or block was seen from Apify servers in these runs; if the portal ever starts refusing the server, the run ends with a message saying so instead of hammering it.

**What happens on a run that is too big?** It stops before the run timeout, keeps everything read so far and ends successfully with "Stopped before the run timeout: N rows saved; raise the timeout or split the job" — verified in the cloud (run `794lgeEtNwK78UyW8`: a 1000-row request with customer details saved 6 rows inside a 60-second timeout and said so). Same for the spending limit. Rows are written page by page, never in one push at the end.

**How deep can one search go?** The portal shows at most **10,000 results per search**, however many it reports. To reach further back, narrow the search — a keyword, a customer, an amount band or a financial year — and run it once per slice.

**Why is the text Russian or Kazakh?** Because that is how the purchases are filed. Names, methods and statuses are passed through untranslated; nothing is machine-translated. The keyword is sent to the portal as typed, so a Latin transliteration will not match — use the Russian or Kazakh word.

**Are the amounts with VAT?** They are the figures the portal publishes, which for most announcements are stated without VAT. The actor does not recalculate them.

**Is `financialYear` always filled?** Only when you pin a year in the input. The search pages do not print the budget year of a row, and the actor never invents one.

**Why is there no contact person in the output?** The announcement page also prints a contact person's name, position and e-mail address. Those are deliberately never read or written: the job — what is bought, by whom, for how much — does not need a person.

**Which pages are read?** Only the public search and announcement pages of the portal (`/ru/search/announce`, `/ru/search/lots`, `/ru/announce/index/<id>`), which `robots.txt` allows. The portal's machine interface needs a registered token, so it is not used; no login, no captcha, no proxy and no browser are involved.

**Wrong filter value?** `method` and `status` take free text: the Russian name, the Kazakh name of a method, another case or spacing, or the numeric id. Anything else stops the run with "did you mean …" and the closest names — the actor never silently substitutes a different method. `mode` is a fixed list, so the platform itself refuses a value other than `announcements` or `lots` before the run starts. A column name in `fields` that does not exist is reported in the run status.

**Empty result?** When nothing on the portal matches, the run succeeds with zero rows and a status naming the filters that matched nothing. If the portal's page layout ever changes so the results table cannot be read, the run fails loudly instead of reporting an empty success.

**Questions or problems:** open an issue on the Issues tab of this actor.

***

Made by **Yadroo**. Sibling actors: [hh-kz-vacancies](https://apify.com/yadroo/hh-kz-vacancies), [krisha-kz](https://apify.com/yadroo/krisha-kz), [kolesa-kz](https://apify.com/yadroo/kolesa-kz), [kaspi-kz-products](https://apify.com/yadroo/kaspi-kz-products), [world-bank-procurement](https://apify.com/yadroo/world-bank-procurement).

# Actor input Schema

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

Two different jobs. `announcements` answers "which tenders were published": one row per announcement with its total amount, procurement method, status and the dates applications are accepted - the view compliance officers, analysts and journalists work in. `lots` answers "what is actually being bought": one row per lot with the lot name, its description, the quantity and the lot amount - the view a supplier needs to decide whether to bid. Both modes read the portal's public search and both rows name their mode in `mode`.

## `query` (type: `string`):

Substring the portal searches in the announcement name, and in the lot name as well when the mode is `lots`. It is sent to the portal exactly as you type it, because the portal does the matching itself - so Russian and Kazakh words both work (`ремонт`, `страхование`, `компьютер`, `жөндеу`), capitals are ignored by the portal and a part of a word matches longer forms. Latin transliteration does not match: the portal stores the names as they were filed, in Russian or Kazakh. Left empty, the run returns the newest announcements with no name filter.

## `customer` (type: `string`):

Substring of the name of the state body or company that buys - `школа`, `больница`, `КазМунайГаз`, `акимат`. The portal matches it inside the full registered name, so a short word is enough and a full name works too. Sent as typed, like the keyword above. The search page names the buying body only in a note under the announcement; switch on "Add customer details" below to get it as columns - `customerName`, `customerBin` and the registered address.

## `announcementNumber` (type: `string`):

Look up a single announcement by the number the portal prints, with or without its lot suffix: `17911453` and `17911453-1` both work. The portal narrows the search to that one announcement, so the run costs one request and writes one row (or none, when the number does not exist). Leave it empty for a normal search; combined with the other filters it still wins, because only one announcement can match.

## `method` (type: `array`):

One procurement method per line, written as the portal prints it in Russian: `Открытый конкурс`, `Запрос ценовых предложений`, `Аукцион`, `Из одного источника по несостоявшимся закупкам`. Case, extra spaces and the Kazakh spelling of the same method are accepted, and the portal's own numeric method id (for example `2` for an open competition) is accepted too. A value that matches nothing stops the run and names the closest methods instead of quietly returning another method's tenders. The full list is in README -> Reference. Empty = every method.

## `status` (type: `array`):

One status per line as the portal prints it: `Опубликовано`, `Опубликовано (прием заявок)`, `Завершено`, `Отменено`, `Отказ от закупки`. Case, extra spaces and the portal's numeric status id (for example `350` for a finished announcement) are accepted; anything else stops the run with the closest statuses named. Use `Опубликовано` and `Опубликовано (прием заявок)` to see only tenders still open for bids, and `Завершено` to study what was already bought. The lot registry has its own, shorter status list. Empty = every status.

## `amountFrom` (type: `integer`):

Keep only announcements (or lots) whose published amount is at least this many tenge, VAT excluded as the portal reports it. `500000000` isolates the half-billion-tenge purchases that are worth a look one by one; the small office buys disappear.

## `amountTo` (type: `integer`):

Upper bound of the published amount in tenge. Combine it with the lower bound to work through one size band at a time - a market study of purchases between 1 and 10 million tenge, for example.

## `financialYear` (type: `integer`):

The budget year the purchase belongs to, which is not always the year it was published: a tender for the next year appears late in the current one. Empty = every year the portal holds, newest announcements first, which is what a monitoring task wants.

## `sinceDays` (type: `integer`):

Keep only rows whose application-start date falls inside this many days back from today (UTC). The portal has no date filter of its own, so this is applied to the dates printed on the search page, and paging stops once a whole page is older than the cutoff - which makes a daily or hourly schedule cheap. Empty = no date cutoff.

## `onlyNew` (type: `boolean`):

Remember the announcement or lot number of every row written, and on the next run of the same actor or task write only numbers that were not written before - so a schedule appends what appeared since the last run instead of resending and recharging the whole search. The first run writes everything that matches. The memory belongs to the actor or task, so two tasks watching two customers never mix. A row whose status changed later is not resent.

## `includeCustomer` (type: `boolean`):

Off (default): rows are built from the search pages only, which is one request per 100 rows. On: the announcement page of every row is opened as well to add `customerName`, `customerBin`, `customerAddress`, `subjectType`, `purchaseType` and `lotCount`. The portal asks crawlers for five seconds between requests and we keep to it, so one extra row costs about five seconds - use it with a small row cap. Contact people named on those pages are never written out.

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

Hard cap on the rows this run writes, and so on what it costs. Results arrive newest announcement first, so a capped run holds the most recent tenders. The portal serves up to 100 rows per request and shows at most 10,000 results for one search - narrow the search with a keyword, a customer, an amount band or a year to reach further back than that.

## `fields` (type: `array`):

Keep only the named columns, in this order - for example `announcementNumber, announcementName, amountTenge, applicationEndDate`. Empty = every column. `mode`, `announcementNumber`, `announcementName`, `amountTenge`, `status`, `url` and `fetchedAt` are always written; name one of them here and it moves to the position you gave it. An unknown name is reported in the run status rather than dropped in silence.

## Actor input object example

```json
{
  "mode": "announcements",
  "query": "ремонт",
  "onlyNew": false,
  "includeCustomer": false,
  "maxItems": 50
}
```

# Actor output Schema

## `results` (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 = {
    "query": "ремонт"
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/goszakup-kz-tenders").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 = { "query": "ремонт" }

# Run the Actor and wait for it to finish
run = client.actor("yadroo/goszakup-kz-tenders").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 '{
  "query": "ремонт"
}' |
apify call yadroo/goszakup-kz-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/goszakup-kz-tenders"
        }
    }
}
```

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/PxYQCSHBz3pImhOxD/builds/iLLavoiNShcrqGR1t/openapi.json
