Skip to main content

koreafilings

Python SDK for koreafilings.com — AI-summarized Korean DART (금융감독원 전자공시) corporate disclosures, paid per call in USDC on Base via the x402 payment protocol.

No API keys. No monthly fee. No signup. The wallet that signs the payment is the identity. Free company-directory and recent-filings feeds let an agent browse before paying; paid endpoints settle on Base mainnet via Coinbase's CDP facilitator. The first call for a disclosure pays the LLM cost; every subsequent call hits the server-side cache for the same flat fee.

Install

pip install koreafilings

Quickstart — name to summary in two calls

The natural agent flow is one free call to resolve a company by name, one paid call to fetch summaries by ticker:

from koreafilings import Client

with Client(private_key="0x...", network="base") as client:
    # 1. Free name → ticker resolution. Matches Korean and English
    #    names with trigram fuzzy search across 3,961 KRX-listed
    #    companies.
    matches = client.find_company("Samsung Electronics")
    ticker = matches[0].ticker  # "005930"

    # 2. Paid batch summary fetch. Price is declared dynamically in
    #    the 402 challenge as 0.005 × limit USDC, so the SDK signs
    #    the exact amount before settling.
    filings = client.get_recent_filings(ticker, limit=5)
    for f in filings:
        print(f"[{f.importance_score}/10] {f.event_type}: {f.summary_en}")

    print("paid:", client.last_settlement.tx_hash)

Example output (one filing returned verbatim from a live Base mainnet paid call against rcpt_no=20260430800106, Samsung Electronics quarterly dividend):

[7/10] DIVIDEND_DECISION: Samsung Electronics decided on a quarterly
  cash dividend of KRW 372 per common share and KRW 372 per preferred
  share, totaling KRW 2,453,315,636,604. The dividend yield is 0.2%
  for common shares and 0.3% for preferred shares. The record date is
  March 31, 2026, with payment scheduled for May 29, 2026.
paid: 0x<base-mainnet-tx-hash>...

The summary is built from the filing body itself (fetched lazily via DART's /document.xml ZIP, parsed and capped at 20,000 chars) rather than the title metadata only — quantitative events surface concrete amounts, percentages, dates, and counterparty names directly in summary_en. For routine governance filings with little body content, the same field falls back to a shorter title-derived summary; the field is always present and never empty.

If you already know the receipt number (e.g. you stored one yesterday and want to re-fetch on the same flat 0.005 USDC tier):

summary = client.get_summary("20260424900874")

Free discovery endpoints

Three endpoints carry no payment challenge so an agent can plan before spending USDC:

# 1. Search by name or ticker (Korean and English, trigram fuzzy):
matches = client.find_company("삼성전자")          # Korean
matches = client.find_company("Samsung Electronics")  # English
matches = client.find_company("005930")            # ticker
for m in matches:
    print(m.ticker, m.name_kr, m.name_en, m.market)

# 2. Direct ticker lookup:
co = client.get_company("005930")

# 3. Browse the market-wide recent feed (metadata only — no LLM
#    summary, but lets the agent see what's hot before paying):
recent = client.list_recent_filings(limit=20)
for r in recent:
    print(r.rcpt_no, r.ticker, r.corp_name, r.report_nm, r.rcept_dt)

Pricing

Endpoint Method Price (USDC)
client.find_company(q) GET /v1/companies free
client.get_company(ticker) GET /v1/companies/{ticker} free
client.list_recent_filings(limit) GET /v1/disclosures/recent free
client.get_recent_filings(ticker, limit) GET /v1/disclosures/by-ticker?ticker=…&limit=… 0.005 × limit
client.get_summary(rcpt_no) GET /v1/disclosures/summary?rcptNo=… 0.005

Per-result pricing on the by-ticker endpoint is declared dynamically in the 402 response: the SDK reads accepts[0].amount from the challenge and signs the exact charge for the requested limit. Direct receipt-number lookup stays at a flat 0.005 USDC.

client.get_pricing() returns the live machine-readable pricing descriptor including the current recipient wallet, network, and USDC contract address.

What you get

get_recent_filings and get_summary return structured Summary objects (or a list[Summary] for the batch endpoint). Each carries:

field type description
rcpt_no str DART receipt number
summary_en str Paraphrased English summary (never verbatim)
importance_score int (1–10) 10 = M&A / insolvency, 1 = routine admin
event_type str Canonical event taxonomy
sector_tags list[str] GICS-style sector labels
ticker_tags list[str] Affected KRX tickers (.KS / .KQ)
actionable_for list[str] Audience hints (traders, long_term_investors, …)
generated_at datetime When the summary was produced

find_company / get_company return Company records (ticker, corp_code, name_kr, name_en, market). list_recent_filings returns RecentFiling records (rcpt_no, ticker, corp_name, report_nm, rcept_dt) — metadata only, no summary.

Getting a wallet and USDC

Production use on Base mainnet:

  1. Create a fresh burner wallet (MetaMask → new account → export private key). Do not reuse an existing personal wallet — the private key signs real-money authorizations.
  2. Fund it with the USDC you intend to spend (a few dollars covers hundreds of summaries).
  3. Pass the 0x-prefixed key to Client(private_key=..., network="base").

For local development against the public testnet facilitator, point the SDK at Base Sepolia:

client = Client(private_key="0x...", network="base-sepolia")

Get free Base Sepolia ETH from the Coinbase faucet and free test USDC from the Circle faucet.

How payment works

Under the hood, each paid call:

  1. GET the endpoint without payment → server returns 402 with an x402 v2 accepts block describing exact amount, USDC contract, network, recipient, and expiry.
  2. SDK signs an EIP-3009 TransferWithAuthorization message locally — your private key never leaves the process.
  3. SDK base64-encodes the signed payload into the PAYMENT-SIGNATURE header (x402 v2 transport spec) and retries the GET.
  4. Server verifies the signature via the x402 facilitator, submits it on-chain, streams the JSON body back, and attaches the settlement proof to the PAYMENT-RESPONSE header. If the facilitator's /settle call rejects, the server fails closed per the x402 v2 spec (HTTP 402 + PAYMENT-RESPONSE failure header + empty body) so the data is never delivered unpaid; the SDK surfaces that as a PaymentError.

The SDK exposes the proof as client.last_settlement so you can log transaction hashes for your accounting system.

Error handling

from koreafilings import Client, ApiError, PaymentError, ConfigurationError

try:
    matches = client.find_company("Samsung Electronics")
    filings = client.get_recent_filings(matches[0].ticker, limit=5)
except PaymentError as e:
    # Facilitator rejected the signed payment (bad sig, low balance,
    # expired auth, network mismatch).
    print("payment failed:", e.reason, e.detail)
except ApiError as e:
    # Non-payment HTTP failure: 404 unknown ticker / rcpt_no, 429
    # rate limit, 5xx upstream outage.
    print("api error:", e.status_code, e.body)
except ConfigurationError as e:
    # Bad private_key format or unknown network alias.
    print("config:", e)

PaymentError.reason vocabulary

A stable string field an agent can branch on without parsing the human message. Same set as the TypeScript SDK uses:

reason Where it fires Recoverable? Recommendation
empty_accepts 402 body has no accepts[] entries — server bug No, terminal Refuse this server
network_mismatch 402 advertises a chain ≠ client's network config Maybe Reconfigure client to match server, or refuse if hostile
payment_rejected Facilitator's /verify rejected the signature Sometimes Check wallet key / clock skew, retry with fresh nonce
settle_failed Facilitator's /settle rejected after a successful verify Sometimes Wait for facilitator to clear, retry with fresh nonce
(facilitator-supplied) A 402 retry returned success:false with a custom errorReason Depends Inspect the message — usually transient

The TypeScript SDK 0.1.2+ adds two more reasons (invalid_network, asset_mismatch) tied to its KNOWN_DOMAINS allowlist; the Python SDK soft-warns on the same conditions today and may add equivalent hard-fail behaviour in 0.4.0. If you write cross-language error handling, branch on reason rather than on exception subclass — the subclass tree is identical, only the reason set differs.

Security notes

  • The private key signs real-money authorizations. Do not ship it in client-side code, do not put it in a .env checked into git, do not paste it in chat. Prefer a dedicated burner wallet funded with only the USDC you plan to spend.
  • The SDK signs locally; the key is never transmitted to koreafilings.com or to the facilitator.
  • Every payment carries an EIP-3009 nonce. The facilitator refuses replays.
  • For Base Sepolia testing only, a fresh wallet with faucet funds is the safest pattern — nothing on that wallet has production value.

TypeScript port

A TypeScript SDK with the same surface ships at koreafilings on npm. If you are porting code line-by-line between Python and TypeScript, watch for these naming differences (defaults, server caps, payment headers, EIP-712 domain handling, and 402 → sign → retry behaviour are byte-identical between the two — only the language-idiomatic surface differs):

Concept Python TypeScript
Constructor Client(private_key=, network=) new KoreaFilings({ privateKey, network })
Method names find_company, list_recent_filings, get_recent_filings, get_summary, get_pricing findCompany, listRecentFilings, getRecentFilings, getSummary, getPricing
HTTP error status ApiError.status_code ApiError.status
Settlement tx hash client.last_settlement.tx_hash client.lastSettlement?.transaction
Settlement error reason last_settlement.error_reason lastSettlement?.errorReason
list_recent_filings arguments kwargs: limit=20, since_hours=24 options object: { limit: 20, sinceHours: 24 }

Source & feedback

MIT-licensed.

Metadata

Release files for koreafilings 0.3.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for koreafilings 0.3.4
File Size Uploaded Provenance
koreafilings-0.3.4.tar.gz 15.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for koreafilings 0.3.4
File Interpreter ABI Platform
koreafilings-0.3.4-py3-none-any.whl Python 3 none any Details

Total release size: 34.6 kB

Release files / koreafilings-0.3.4.tar.gz

Download URL koreafilings-0.3.4.tar.gz
Size 15.8 kB
Tags Source
SHA-256 checksum
How to use checksums
89e73e084fda5c0bb7e326935f57b0952d8566755897c159a88b2b00285972b7
BLAKE2b-256 checksum
How to use checksums
d4cb678211639b55a67dedae26d1cbd524a95e9e6d1f25b99ff56d846ddf926b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / koreafilings-0.3.4-py3-none-any.whl

Download URL koreafilings-0.3.4-py3-none-any.whl
Size 18.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5ab5b79b87ea0726cf30855b98ba22023c8f5f24b3917cf7361c4737e0b2e2fb
BLAKE2b-256 checksum
How to use checksums
0d1176e2b4ec2e6d004122c7b84df11f2813b502e9df6c30100ae50c178226e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for koreafilings 0.3.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page