Korea Filings
Machine-ready English summaries of Korean corporate disclosures (DART · 전자공시), paid per call in USDC over the x402 protocol on Base. Built for AI agents, quant funds, and research platforms that need programmatic access to Korean market events without reading Korean PDFs.
Live: https://koreafilings.com · API at
https://api.koreafilings.com · interactive docs at
/swagger-ui.
What it does
Raw DART data is free, but it's in Korean and structured for human filings clerks, not LLMs. Korea Filings turns every disclosure into a structured, cached, English-summarised JSON payload an agent can consume in one call:
{
"rcptNo": "20260424900874",
"summaryEn": "Global SM's stock trading was temporarily suspended on April 24, 2026, due to a change in electronic registration related to a stock consolidation or split.",
"importanceScore": 10,
"eventType": "SINGLE_STOCK_TRADING_SUSPENSION",
"sectorTags": ["Capital Goods"],
"tickerTags": ["095440"],
"actionableFor": ["traders", "long_term_investors"],
"generatedAt": "2026-04-24T08:47:51Z"
}
The cache is the moat — the first agent to request a disclosure pays
for the LLM run; every subsequent agent for the same rcpt_no hits a
near-zero-cost DB lookup and still pays the same fixed fee. Margins
compound as adoption grows.
How to use it
Pick whichever surface fits your stack. All three speak the same x402
flow under the hood; the wallet that signs the X-PAYMENT header is
the identity. No API keys. No signup.
Python SDK
pip install koreafilings
from koreafilings import Client
with Client(private_key="0x...", network="base") as client:
summary = client.get_summary("20260427901120")
print(f"[{summary.importance_score}/10] {summary.event_type}")
print(summary.summary_en)
print("paid:", client.last_settlement.tx_hash)
MCP server (Claude Desktop, Cursor, Continue, …)
uv tool install koreafilings-mcp
In your MCP client's config:
{
"mcpServers": {
"koreafilings": {
"command": "uv",
"args": ["tool", "run", "koreafilings-mcp"],
"env": {
"KOREAFILINGS_PRIVATE_KEY": "0x...",
"KOREAFILINGS_NETWORK": "base"
}
}
}
}
Two tools become available:
get_pricing— free; returns the live wallet, network, USDC contract, and per-endpoint price.get_disclosure_summary(rcpt_no)— paid; returns the structured summary plus the on-chain settlement transaction hash.
curl / direct HTTP
# 1) Probe the endpoint without payment to discover the requirements.
curl -i https://api.koreafilings.com/v1/disclosures/20260427901120/summary
# HTTP/2 402
# payment-required: <base64 PaymentRequired payload>
# { "x402Version": 2, "accepts": [{ "scheme": "exact", ... }], ... }
# 2) Sign an EIP-3009 TransferWithAuthorization for one of the entries
# in `accepts`, base64-encode the signed PaymentPayload, and resend
# with the X-PAYMENT header. See testclient/payer.py for a 90-line
# reference implementation.
curl -H "X-PAYMENT: $SIGNED" \
https://api.koreafilings.com/v1/disclosures/20260427901120/summary
# HTTP/2 200
# x-payment-response: <base64 SettlementResponse with tx hash>
# { "rcptNo": "...", "summaryEn": "...", ... }
Pricing
| Endpoint | Method | Price (USDC) |
|---|---|---|
/v1/disclosures/{rcptNo}/summary | GET | 0.005 |
The full machine-readable pricing descriptor (current wallet, network,
USDC contract, all paid endpoints) lives at
/v1/pricing.
Live on Base mainnet via the Coinbase CDP facilitator. The first
on-chain settlement is permanent at
0x681c995e… —
a payer wallet moved 0.005 USDC to the merchant wallet
0x8467Be164C75824246CFd0fCa8E7F7009fB8f720 in a single
transferWithAuthorization call.
Architecture
Three logical subsystems share one Spring Boot application:
- Ingestion — schedules a 30-second poll against the DART Open
API, deduplicates by
rcpt_no, persists raw metadata to Postgres, enqueues a summarisation job. - Summarisation — consumes summarisation jobs, classifies
complexity, routes to Gemini 2.5 Flash-Lite (with Resilience4j
rate-limiting + circuit-breaking + retries), persists English
summary + ticker / sector tags + audit row to
llm_audit. - Paid API — Spring MVC controller behind an
X402PaywallInterceptor. Every request: checkX-PAYMENT, verify the signature with the facilitator, check Redis for replay, settle on a 200 response, and attachX-PAYMENT-RESPONSEcarrying the on-chain tx hash via aResponseBodyAdvice. The interceptor short-circuits for handler methods without@X402Paywall, so/v1/pricing,/.well-known/x402, and the OpenAPI document stay unauthenticated.
The 402 challenge follows the
x402 v2 transport spec:
the PAYMENT-REQUIRED header carries the base64-encoded
PaymentRequired payload (with the bazaar
extension declaring an input/output schema for AI-agent
discoverability), while the body keeps a v1-compatible JSON copy so
older clients keep working.
Stack: Java 21, Spring Boot 3.4, PostgreSQL 16, Redis 7, Docker
Compose, Cloudflare Tunnel, Cloudflare Workers, Hetzner CAX11. See
docs/ARCHITECTURE.md for deeper notes.
Repository layout
.
├── src/ # Spring Boot application source
├── sdk/python/ # `koreafilings` Python SDK (PyPI)
├── mcp/ # `koreafilings-mcp` MCP server (PyPI)
├── landing/ # Marketing landing page (Cloudflare Workers)
├── testclient/ # Reference Python x402 client (testnet payer)
├── docs/
│ ├── ARCHITECTURE.md # System design
│ ├── PRD.md # Product requirements
│ ├── ROADMAP.md # Six-week launch plan
│ └── STATUS.md # Operator handoff notes
├── Dockerfile # Multi-stage prod build (eclipse-temurin:21)
├── docker-compose.yml # postgres + redis + app + cloudflared
└── build.gradle.kts # Gradle (Kotlin DSL)
Local development
git clone https://github.com/OldTemple91/korea-filings-api.git
cd korea-filings-api
cp .env.example .env
# Fill in:
# POSTGRES_PASSWORD (any strong password)
# DART_API_KEY (free, register at https://opendart.fss.or.kr/)
# GEMINI_API_KEY (free tier, https://aistudio.google.com/apikey)
# X402_RECIPIENT_ADDRESS (your receiving wallet — only the address)
docker compose up -d postgres redis
./gradlew bootRun
To exercise a real x402 payment against a local instance, copy
testclient/.env.testclient.example to testclient/.env.testclient,
fill in a wallet's private key (a fresh burner wallet funded with a
dollar or two of Base mainnet USDC is the safe pattern), and run
python testclient/payer.py. For local development against the public
testnet facilitator, point X402_FACILITATOR_URL at
https://www.x402.org/facilitator and use Base Sepolia parameters in
your .env.
Status
Live on Base mainnet with verified on-chain settlement (first tx). MVP feature set:
- DART real-time ingestion (30-second poll)
- Gemini 2.5 Flash-Lite summarisation with importance scoring + sector / ticker tagging
- x402 v2 paywall with
bazaarextension for agent-discoverable invocation - Discovery via
/.well-known/x402 - OpenAPI 3 spec at
/v3/api-docs+ interactive Swagger UI - Python SDK and MCP server published to PyPI
- Indexed by x402scan
- Production deploy on Hetzner via Cloudflare Tunnel
- Coinbase CDP facilitator (Ed25519 JWT auth) for mainnet settlement
Coming next:
- Additional paid endpoints:
/disclosures/latest,/by-ticker/{ticker},POST /filter, SSE/stream,/impact - TypeScript SDK
- Korean-language landing page
- Slack / email alerts on settlement
See docs/ROADMAP.md for the full plan.
Contributing
Issues and PRs are welcome — particularly:
- Ports of the Python SDK to other languages (TypeScript, Go, Rust)
- Additional analytics endpoints (price reaction, comparable filings, …)
- Integrations with non-x402 agent frameworks
- Translation of the landing page into other languages
For substantial changes, please open an issue first describing the direction so we can sanity-check fit before you build.
License
MIT.