What it covers
ECOS is the authoritative starting point for Bank of Korea statistics. It exposes catalog discovery, item lookup, statistical observations, key indicators, and release-calendar style information using stable statistical table and item codes.
Request shape
GET https://ecos.bok.or.kr/api/StatisticSearch/{API_KEY}/json/kr/1/10/{STAT_CODE}/{CYCLE}/{START}/{END}/{ITEM_CODE}
Start with the catalog endpoints, record the selected table and item codes, then query the actual time series. Store those codes alongside the data so later refreshes remain auditable.
Key endpoints
| Endpoint pattern | Description |
|---|---|
StatisticSearch/{key}/json/kr/1/10/731Y001/D/{from}/{to}/0000001 |
USD/KRW exchange rate (731Y001) |
StatisticSearch/{key}/json/kr/1/100/731Y001/D/{from}/{to}/ |
All major currency rates |
StatisticSearch/{key}/json/kr/1/10/060Y001/M/{from}/{to}/ |
Consumer price index |
StatisticSearch/{key}/json/kr/1/10/102Y004/M/{from}/{to}/ |
Policy interest rate |
StatisticItemList/{key}/json/kr/1/100/731Y001 |
List items in a statistic |
Decision notes
Prefer ECOS over secondary macro-data vendors when the required Korean series is available. Treat release timing, revisions, units, and frequency as part of the observation—not as display-only metadata.
Python examples
1. USD/KRW rate with fallback patterns
import httpx
from decimal import Decimal
from datetime import datetime
API_KEY = "your_ecos_api_key"
BASE = "https://ecos.bok.or.kr/api"
def fetch_usd_krw(dt: datetime) -> Decimal | None:
"""Fetch USD/KRW for a date, trying multiple URL patterns.
ECOS API behavior varies; trying several patterns increases success rate.
731Y001 = major currency rates vs KRW (most reliable source).
"""
date_str = dt.strftime("%Y%m%d")
patterns = [
f"{API_KEY}/json/kr/1/10/731Y001/D/{date_str}/{date_str}/0000001",
f"{API_KEY}/json/kr/1/100/731Y001/D/{date_str}/{date_str}/",
]
for pattern in patterns:
try:
resp = httpx.get(f"{BASE}/StatisticSearch/{pattern}", timeout=12)
resp.raise_for_status()
rate = parse_usd_rate(resp.json())
if rate:
return rate
except Exception:
continue
return None
def parse_usd_rate(data: dict) -> Decimal | None:
"""Extract USD/KRW from ECOS response. Handles varying structures."""
outer = data.get("StatisticSearch") or data
# rows may be under 'row', 'rows', 'list', or 'stat'
rows = outer.get("row") or outer.get("rows") or []
if isinstance(rows, dict):
rows = [rows]
for row in rows:
# Match by item name since codes can vary
name = row.get("ITEM_NAME1", "")
if "미국달러" in name and "매매기준율" in name:
value = row.get("DATA_VALUE", "").replace(",", "").strip()
if value and value != "-":
return Decimal(value)
return None
2. Previous business day fallback
from datetime import timedelta
def get_rate_with_fallback(dt: datetime, max_days_back: int = 5) -> Decimal | None:
"""Get rate for a date, falling back to previous business days.
ECOS doesn't publish on weekends/holidays. Walk back up to
5 days, skipping weekends, until a rate is found.
"""
# Try the requested date first
rate = fetch_usd_krw(dt)
if rate:
return rate
# Walk back, skipping weekends
for days_back in range(1, max_days_back + 1):
prev = dt - timedelta(days=days_back)
if prev.weekday() >= 5: # Saturday, Sunday
continue
rate = fetch_usd_krw(prev)
if rate:
return rate
return None
3. Caching strategy
# ECOS allows ~100 calls/hour. For daily FX rates, cache by date.
# A simple dict works for scripts; use SQLite/Redis for services.
_cache: dict[str, Decimal] = {}
def get_cached_rate(dt: datetime) -> Decimal | None:
key = dt.strftime("%Y%m%d")
if key not in _cache:
_cache[key] = get_rate_with_fallback(dt)
return _cache[key]
Real-world notes:
- Rate limit: ~100 calls/hour — daily caching is sufficient for FX rates
- Weekends/holidays: No data published; always implement previous-business-day fallback
- Response structure varies: Check
StatisticSearch.row, handle both list and single-dict - Item matching: Match by
ITEM_NAME1containing “미국달러” rather than hardcoding item codes - DATA_VALUE: May contain commas or “-” for missing; strip and validate before
Decimal() - Statistic code
731Y001: Major currency rates vs KRW — the most reliable source for USD/KRW
Integration surface
- Versioning
- Service-name request paths; no global version prefix is documented in the reviewed developer guide.
- Resource groups
- StatisticSearch, StatisticTableList, StatisticItemList, KeyStatisticList
- Pagination
- Start and end row numbers are embedded in request paths.
- Errors
- Responses include ECOS result codes and messages; inspect them before reading rows.
- Webhooks
- No webhook interface was confirmed in the reviewed ECOS developer guide.
- Official SDKs
- None confirmed in the reviewed official sources.