# KONEPS Bid Notice Change Detector (`honjahoesa/koneps-bid-change-detector`) Actor

나라장터(KONEPS) 입찰공고의 신규·정정·삭제 변경만 감지해 알려주는 모니터링 Actor. 공식 무료 data.go.kr API(BYOK), 스케줄 실행, 웹훅, 데모 모드. Detects new, updated and removed bid notices on Korea's KONEPS procurement portal via the official free data.go.kr API. Snapshot diff per run; webhook alerts; demo mode without API key.

- **URL**: https://apify.com/honjahoesa/koneps-bid-change-detector.md
- **Developed by:** [Dongjin Kim](https://apify.com/honjahoesa) (community)
- **Categories:** Business, Automation
- **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

## KONEPS Bid Notice Change Detector (나라장터 입찰공고 변경 감지기)

**무엇을 하나요?** 나라장터(KONEPS) 입찰공고에서 \*\*새로 올라온 공고(NEW), 정정된 공고(UPDATED), 사라진 공고(REMOVED)\*\*만 골라 알려주는 감시 도구입니다. 매일 나라장터를 뒤지는 대신, 스케줄에 걸어두면 변경분만 받습니다. Detects **new, updated, and removed** bid notices on Korea's KONEPS (나라장터) public procurement portal and reports only the diff on every run.

**데이터 출처**: 조달청 공식 **공공데이터포털(data.go.kr) Open API** (이용허락 제한 없음). 스크래핑·프록시·브라우저 자동화 없음. No scraping, no proxies - the official free 조달청_나라장터 입찰공고정보서비스 API.

### 2분 체험 (API 키 없이) / Try it in 2 minutes (no API key)

1. **그냥 실행**을 누르세요 - 데모 모드가 기본으로 켜져 있습니다. 첫 실행은 기준선을 만듭니다. Just press **Start** - demo mode is ON by default. The first run builds the baseline.
2. **한 번 더 실행**하세요 - 샘플 `NEW` / `UPDATED` / `REMOVED` 행이 출력됩니다 (DEMO 표기, 실제 API 호출 없음). Run it **a second time** - you get sample change rows clearly marked `DEMO`.

샘플 출력 예시 / Sample output:

```json
{
  "changeType": "UPDATED",
  "bidNtceNo": "DEMO-2026-0001",
  "bidNtceNm": "DEMO 2026년 지능형 입찰정보 시스템 유지보수 용역 (정정)",
  "ntceInsttNm": "DEMO조달청",
  "bidClseDt": "2026-10-26 18:00",
  "asignBdgtAmt": "120000000",
  "bidNtceDtlUrl": "https://www.g2b.go.kr/"
}
```

**왜 두 번 실행하나요?** 변경 감지는 "이전 실행 스냅샷 vs 지금" 비교라서 첫 실행은 기준선 저장만 합니다. Change detection compares the current result against your previous run's snapshot, so the first run only stores the baseline.

### 실제 데이터로 사용 / Use with live data

1. 공공데이터포털에서 **무료 API 키** 발급 (자동 즉시 승인, 비용 없음): https://www.data.go.kr/data/15129394/openapi.do
2. 키를 `serviceKey`에 붙여넣고 **데모 모드 OFF** / paste the key into `serviceKey` and turn demo mode OFF.
3. **태스크 + 스케줄** 생성 (예: 6시간마다). 조회 창(기본 48시간)은 스케줄 간격보다 약간 길게. Create an Actor **task** with your filters and attach a **schedule**; keep the look-back window a bit longer than the interval.

### What it does / 기능

1. Queries the official KONEPS bid-notice API for the categories you choose (용역 services / 물품 goods / 공사 construction), optionally filtered by keyword and agency.
2. Compares the result against the snapshot from your previous run (per filter profile, in the named key-value store `koneps-snapshots`, retained indefinitely).
3. Outputs one dataset row per change: `NEW`, `UPDATED`, or `REMOVED`, with notice fields (공고번호, 공고명, 공고기관, 마감일시, 배정예산, 상세 링크).
4. Optionally POSTs a JSON summary to your webhook URL.

### Cost & pricing

Currently published free of charge (pay-per-usage: you only pay Apify platform usage, which depends on your actual run frequency and settings). A pay-per-event price may be introduced later; any pricing change will be announced in advance under Apify's pricing-change policy.

### Honest limitations

- Change history here means the diff between your runs. For the official per-notice correction history (정정이력), see the KONEPS portal directly.
- All result pages are fetched per category, capped by the `maxPagesPerType` input (default 30 pages = 3,000 notices). Lower it to protect the free data.go.kr daily quota (1,000 calls/day). If the API fails or a result set is truncated, that category's snapshot is preserved and no REMOVED judgment is made, so an outage is never misreported as mass removals.
- Demo mode uses bundled sample data and makes no live API call.

### Reliability notes

- Snapshots live in the named key-value store `koneps-snapshots`. Under Apify's current storage policy, named stores have no automatic expiry, so pausing a schedule for weeks should not reset the baseline - see Apify's docs for the current retention terms.
- If any category fetch fails or is truncated, that category's snapshot is preserved and no REMOVED judgment is made; the run summary carries an `incompleteFetch` warning and per-category `fetchStatus`.
- Free data.go.kr development keys allow 1,000 API calls/day; a typical run with a 48-hour window uses under 10 calls.

***

## 한국어 안내 (Korean guide)

**나라장터(KONEPS) 입찰공고 변경 감지기** — 조달청 공식 API로 용역·물품·공사 공고를 조회하고, 이전 실행과 비교해 **신규(NEW)·정정(UPDATED)·삭제(REMOVED)** 된 공고만 알려줍니다. 스케줄에 걸어두면 내 키워드·기관 조건에 맞는 변화만 자동으로 잡아줍니다.

### 빠른 시작

1. **키 없이 체험**: 그대로 실행(데모 모드 기본 ON) → 한 번 더 실행하면 샘플 변경 결과(DEMO 표기)를 볼 수 있습니다.
2. **실제 데이터**: 공공데이터포털에서 무료 키 발급(자동 즉시 승인, 비용 없음): https://www.data.go.kr/data/15129394/openapi.do → 키를 `serviceKey`에 입력하고 데모 모드 OFF.
3. **자동 감시**: Actor 태스크를 만들고 스케줄(예: 6시간마다)을 연결. 조회 창(기본 48시간)은 스케줄 간격보다 약간 길게.

### 안내 사항

- 첫 실행은 기준선(스냅샷)만 만들고, 변경 감지는 두 번째 실행부터입니다. 스냅샷은 named 저장소(`koneps-snapshots`)에 보관되며, 현재 Apify 정책상 named 저장소는 자동 만료가 없어 스케줄을 오래 멈춰도 기준선이 유지됩니다(최신 보관 정책은 Apify 문서 참조).
- API 장애나 조회 잘림이 감지되면 해당 분야의 스냅샷을 그대로 보존하고 삭제(REMOVED) 판정을 하지 않습니다. 일시 장애가 '공고 대량 삭제'로 잘못 알려지는 일은 없습니다.
- 무료 개발계정 기준 하루 1,000회 API 호출 제한이 있으며, 일반적인 실행은 10회 미만을 씁니다. `maxPagesPerType`으로 상한을 조절할 수 있습니다.
- 현재 무료로 공개되어 있습니다. 유료 전환 시 14일 전에 사전 고지합니다.
- 문의·개선 제안은 Actor 이슈로 남겨 주세요.

# Actor input Schema

## `serviceKey` (type: `string`):

공공데이터포털 무료 키 (조달청_나라장터 입찰공고정보서비스, 자동 즉시 승인·무료). 발급: https://www.data.go.kr/data/15129394/openapi.do — 데모 모드에서는 불필요. Your free data.go.kr API key (instant auto-approval, no cost). Not needed in demo mode.

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

선택. 공고명에 이 텍스트가 포함된 공고만 추적 (예: 소프트웨어, 유지보수). 비우면 전체. Optional: only notices whose title contains this text.

## `agency` (type: `string`):

선택. 기관명에 이 텍스트가 포함된 공고만 추적 (예: 한국전력). Optional: only notices from agencies matching this text.

## `types` (type: `array`):

조회할 나라장터 분야 선택. Which KONEPS categories to check.

## `dateWindowHours` (type: `integer`):

지금부터 몇 시간 전까지의 공고를 조회할지 (공고일시 기준). 스케줄 간격보다 약간 길게 설정 권장. 1-720. How far back to query; keep it a bit longer than your schedule interval.

## `webhookUrl` (type: `string`):

선택. 변경 발견 시 JSON 요약을 POST할 HTTPS 주소. Optional HTTPS URL that receives a JSON summary when changes are found.

## `testMode` (type: `boolean`):

번들 샘플 데이터로 전체 흐름을 체험 (실제 API 호출 없음, DEMO 표기). 키 입력 후에는 OFF로 전환하세요. Try the full flow with bundled sample data; turn OFF after adding your key.

## `apiBaseUrl` (type: `string`):

Advanced: override the official API base URL, e.g. for testing against a mock server.

## `maxPagesPerType` (type: `integer`):

분야당 조회 페이지 상한 (페이지당 100건). 무료 일일 쿼터(1,000회) 보호용. 초과 시 해당 분야는 불완전 처리되어 삭제 판정을 하지 않습니다. Safety cap protecting your free daily quota; exceeding categories are marked incomplete with no REMOVED judgment.

## Actor input object example

```json
{
  "types": [
    "servc",
    "thng",
    "cnstwk"
  ],
  "dateWindowHours": 48,
  "testMode": true,
  "apiBaseUrl": "https://apis.data.go.kr/1230000/ad/BidPublicInfoService",
  "maxPagesPerType": 30
}
```

# Actor output Schema

# 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 = {
    "types": [
        "servc",
        "thng",
        "cnstwk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("honjahoesa/koneps-bid-change-detector").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 = { "types": [
        "servc",
        "thng",
        "cnstwk",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("honjahoesa/koneps-bid-change-detector").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 '{
  "types": [
    "servc",
    "thng",
    "cnstwk"
  ]
}' |
apify call honjahoesa/koneps-bid-change-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,honjahoesa/koneps-bid-change-detector"
        }
    }
}
```

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/oWSKH941qb8ZC038j/builds/bE02tXJ9hK8o3bmR3/openapi.json
