G2b Cli
v0.1.0Korean public procurement (나라장터 g2b.go.kr) command-line wrapper for the 조달청 OpenAPI surface — three subcommands cover BidPublicInfoService (입찰공고 per 업무구분 thn...
g2b-cli
Command-line wrapper for 조달청 나라장터 OpenAPI — Korea's first-party public-procurement system. 나라장터 (g2b.go.kr) is the single national platform every Korean government agency, public university, and SOC project must use to post tenders worth roughly ₩200T per year. The 조달청 (Public Procurement Service) exposes three OpenAPI services on data.go.kr that mirror the website's three core surfaces: 입찰공고, 계약현황, and the 개방표준 data feed.
Three subcommands wrap the surface:
| Command | Service | Purpose |
|---|---|---|
scripts/bid.sh | BidPublicInfoService | 입찰공고 (current bidding announcements) per 업무구분 + PPS keyword search. |
scripts/contract.sh | CntrctInfoService | 계약현황 (signed-contract listings) per 업무구분. |
scripts/std.sh | PubDataOpnStdService | 개방표준 unified feed: bid / awarded / contract on one canonical schema. |
All output is JSONL — one row per record — so it pipes directly into jq, csvkit, pandas, or downstream skills. Pass --meta to any subcommand to get {totalCount, pageNo, numOfRows} instead of the items, which is the right shape for paging loops.
When to use this skill
- Tender-monitoring dashboards —
bid.sh --type servc --keyword "AI"every hour to surface new AI-related RFPs nationwide. Pair with email/Slack alerts. - Awarded-contract scrapers —
std.sh --what awarded --from 202601010000 --to 202612310000to backfill the year's 낙찰 records into a warehouse with a single, schema-stable feed. - Supplier KYB on awardees — pull
bizrnofrom awarded records, fan out tonts-bizno-cli statusto confirm the company is still 정상사업자 before you sign downstream paperwork. - B2B sales prospecting —
bid.sh --type thng --inquiry-div 5 --dminstt-cd <기관>to monitor a target buyer institution's tender pipeline. - Construction / SOC analysts —
contract.sh --type cnstwk --from --tofor monthly 공사 contract volumes by region; pair withkosis-clifor population/GDP normalisation. - Compliance audits — repeated calls with
--metagive totals; reconcile against a third-party data vendor's claims. - News grounding for AI agents — when an LLM answers "who won the Seoul subway camera tender?", cite real records from
std.sh --what awardedinstead of hallucinating.
Do not use this skill for
- Bid submission — the OpenAPI is read-only. Actual bid filing requires the 나라장터 GPKI/GBKI digital cert + browser session — that's still a Windows-only ActiveX/exe flow as of 2026.
- Pre-RFP procurement plans (사전공고) — those live on a separate 조달정보표준 service not yet covered here.
- Sub-minute polling — data.go.kr dev keys are 1,000 req/day. For live aggregation in production, request the prod tier on data.go.kr (justification + use-case form, ~3 business days).
- Outside-Korea procurement — only 나라장터-listed Korean public tenders. For EU TED, US SAM.gov, or KONEPS/KOICA-funded foreign tenders, use those systems directly.
- Sub-public tenders (private B2B RFPs) — Korea's 나라장터 does not host private-sector RFPs. Use third-party platforms (BidWeb, EProcurement) for that.
Prerequisites
- Register at https://www.data.go.kr/ (free, no business required).
- Apply for all three services (instant approval, dev tier; production tier needs a usage-case form):
- "조달청_나라장터 입찰공고정보서비스" (BidPublicInfoService)
- "조달청_나라장터 계약현황정보" (CntrctInfoService)
- "조달청_나라장터 공공데이터개방표준서비스" (PubDataOpnStdService)
- Copy the Decoding key (the raw form, not URL-encoded) and export:
export G2B_SERVICE_KEY='your_decoded_key_here' - Optional overrides (rarely needed; useful for staging):
export G2B_BID_BASE='https://apis.data.go.kr/1230000/ad/BidPublicInfoService' export G2B_CNTRCT_BASE='https://apis.data.go.kr/1230000/ao/CntrctInfoService' export G2B_STD_BASE='https://apis.data.go.kr/1230000/ao/PubDataOpnStdService'
Common workflows
A) Today's new 용역 (services) tenders
scripts/bid.sh --type servc --rows 200 \
| jq -c '{bidNtceNo, bidNtceNm, ntceInsttNm, dminsttNm, presmptPrce, bidNtceDt, bidBeginDt}'
B) Keyword-driven RFP alert (AI-related 용역)
scripts/bid.sh --keyword "인공지능" --rows 50 \
| jq -c 'select(.bidNtceDt >= "2026-04-01") | {bidNtceNo, bidNtceNm, presmptPrce, ntceInsttNm}' \
| tee today_ai_rfps.jsonl
C) Last-week awarded contracts → warehouse
# Use the open-standard feed for warehouse-ready, schema-stable rows.
scripts/std.sh --what awarded --from 202604220000 --to 202604290000 --rows 500 \
> awarded_2026wk17.jsonl
D) Awardee KYB chain (g2b → nts-bizno)
# 1. Pull awarded list.
scripts/std.sh --what awarded --rows 100 > awarded.jsonl
# 2. For each awardee 사업자번호, confirm 정상사업자 status.
jq -r '.bizrno // empty' awarded.jsonl | sort -u | while read brn; do
nts-bizno-cli status --b-no "$brn" \
| jq --arg brn "$brn" '{bizrno: $brn, taxType: .tax_type, businessStatus: .b_stt}'
done > awardee_kyb.jsonl
E) One specific 공고 detail (when you have the bidNtceNo)
scripts/bid.sh --type thng --bid-no 20240412345-00 --rows 1 | jq .
F) Buyer-institution tender pipeline (수요기관 기준)
# 6110000 = 서울특별시청 (example dminsttCd; look up via the 나라장터 institution dictionary).
scripts/bid.sh --type cnstwk --inquiry-div 5 --dminstt-cd 6110000 --rows 200 \
| jq -c '{bidNtceNo, bidNtceNm, presmptPrce, opengDt}'
G) Pagination loop (full month dump)
month_from=202604010000; month_to=202604300000
scripts/std.sh --what bid --from $month_from --to $month_to --meta
# {"totalCount":4982,"pageNo":1,"numOfRows":100}
for p in $(seq 1 50); do
scripts/std.sh --what bid --from $month_from --to $month_to --rows 100 --page $p \
>> bid_2026_04.jsonl
done
Data shapes (high-signal fields)
bid.sh (BidPublicInfoService) — non-exhaustive list:
| Field | Meaning |
|---|---|
bidNtceNo | 입찰공고번호 (primary key) |
bidNtceOrd | 차수 (revision; 00 = original) |
bidNtceNm | 입찰공고명 |
ntceInsttNm | 공고기관명 (the institution that posted) |
dminsttNm | 수요기관명 (the institution that will use it) |
presmptPrce | 추정가격 (원) |
bidNtceDt | 공고게시일자 |
bidBeginDt | 입찰개시일시 |
opengDt | 개찰일시 |
bidMethdNm | 입찰방식 |
cntrctCnclsMthdNm | 계약체결방법 |
contract.sh (CntrctInfoService) — non-exhaustive list:
| Field | Meaning |
|---|---|
cntrctNo | 계약번호 (primary key) |
cntrctNm | 계약명 |
cntrctMthdNm | 계약방식 |
cntrctCnclsDate | 계약체결일자 |
cntrctPrce | 계약금액 (원) |
bizrno | 낙찰자 사업자등록번호 |
corpNm | 낙찰자 상호 |
std.sh --what awarded — non-exhaustive list:
| Field | Meaning |
|---|---|
bidNtceNo | 입찰공고번호 |
opengDate | 개찰일자 |
sucsfbidAmt | 낙찰금액 (원) |
sucsfbidRate | 낙찰률 (%) |
bizrno | 낙찰자 사업자등록번호 |
corpNm | 낙찰자 상호 |
Field names are stable inside each --what mode of std.sh but vary across the four 업무구분 in the non-std endpoints — always inspect a row before assuming a key exists.
Pairs naturally with
- nts-bizno-cli — resolve every
bizrnoin awarded records to a tax-type + business-status (KYB on the supplier side). - juso-address-cli — geocode 수요기관/공고기관 addresses to a 행정동 + WGS84.
- kakao-local-cli — map-pin the resolved coordinates for a regional tender map.
- opendart-cli — cross-check listed-company awardees against their public disclosures (ownership, financials, related-party).
- kr-holiday-cli — calendar-overlay tenders to detect off-cycle posting (often a sign of urgency or favoritism).
- tistory-api-cli / velog-cli — publish daily/weekly tender-digest posts (e.g., "AI 입찰 모음 — 2026-04-29").
Implementation notes
- All endpoints accept both XML and JSON (
type=json). This skill always asks for JSON; the wrapper will hard-fail with a clear message if the upstream returns XML (the 조달청 service silently falls back to XML on a serviceKey error). - Date params on g2b are 12-digit
YYYYMMDDHHMM— the wrapper validates this and provides a sensible default (last 7 days) when neither--from/--tonor--bid-nois given. inqryDiv(조회구분) defaults match what the official portal example shows:1for date-window queries,3for--bid-no,4for--instt-cd,5for--dminstt-cd. Override with--inquiry-divif you need 등록 vs. 공고게시 vs. 개찰일자 selection.- The keyword search (
--keyword) targetsgetBidPblancListInfoServcPPSSrch— only 용역 has a documented PPS keyword endpoint. For 물품/공사/외자, post-filter withjq 'select(.bidNtceNm | test("키워드"))'instead. - The wrapper validates the
response.header.resultCode == "00"envelope and surfacesresultMsgon failure — common codes:30(서비스키 미등록),22(LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS — daily quota hit),11(NODATA_ERROR — empty result, not a failure shape; the wrapper still treats this as an error so you'll know upstream returned nothing).
Examples
See examples/ for end-to-end recipes including: AI-keyword RFP digest, weekly 낙찰 ETL, awardee KYB pipeline, regional construction-contract map.
Key takeaways
- Three subcommands cover the entire 조달청 OpenAPI public surface. Pick
std.shfirst when you want one canonical schema; pickbid.sh/contract.shwhen you need the per-업무구분 fields the open-standard feed strips. - This is the read side of 나라장터; bid submission is intentionally out of scope.
- Pair with
nts-bizno-clifor end-to-end awardee-vetting in a single shell pipeline — the missing piece between "the contract was awarded" and "the awardee is currently a 정상사업자".
