Korea Data

Conventions

These rules hold for every endpoint, in every dataset. Each endpoint page describes only what is particular to it.

https://notonlystock.com/korea/api/v0

Authentication

Authorization: Bearer kcid_...

Create a key on the account page — up to 10 active keys. Keys are stored hashed: the plaintext is shown once, at creation. Revoking a key takes effect on the next call.

Server-side only. No Access-Control-* headers are sent, so a browser page cannot call this API directly — the request fails as a CORS error before your code sees a status. Call it from your server and keep the key there, which is also where a key belongs.

Credits

Prepaid credits, not a subscription. There are three shapes, and every endpoint says which one it is:

Per callA fixed amount for one thing — a company record, an employment series, one address
Per rowCharged for rows returned, never for the call. limit is what controls the bill
Free0 credits. Catalogue and account calls, so you can see what exists and what you have before spending

Nothing is charged for nothing. A lookup that finds no company, a search that returns no rows, and any error response all cost 0. The one exception is count_only=true, a flat 100 whatever the count, including zero — it does work you asked for. Balances are drawn from the free signup allowance first, so it is used before it can expire. What each call costs →

Two names for the same number. Company responses report credits_spent; rail and address responses report credits_charged. Same meaning. This will be one name before v1 — see versioning.

Paging

Row-priced endpoints page with a cursor. A full page comes back with next_cursor; send it as cursor for the next one. No next_cursor means you have reached the end. limit goes up to 1,000.

# → { "returned": 1000, "next_cursor": "22237.1428145237", ... }
curl -H "Authorization: Bearer $KCID_API_KEY" ".../companies/search?industry=26&limit=1000&cursor=22237.1428145237"

Paging costs the same as one large call — the price is per row either way. The cursor is positional, not a snapshot: if the data changes between pages, rows can shift. For a consistent extract, pull the pages in one sitting.

Bulk extraction is expected, not discouraged. Pulling the whole rail timetable is 656 calls, and that is a normal way to use it. There is no cap on how fast you spend credits you paid for.

Limits

Calls that spend credits are not rate limited. Your credits are the limit. Capped at 1,000 a day per key are calls that spend nothing — lookups that find nothing, searches that match nothing, errors, account and catalogue calls — and /addresses, which is capped even though it costs 1 credit. That one queries a government register on every call, so the cap protects the register, not our capacity. Past it you get 429 daily_call_cap; every other credit-spending call keeps working.

Errors

StatusCodeMeans
400bad_query · bad_cursor · missing_query · query_too_longA filter value or cursor we do not accept. The message names what is accepted — a typo should not look like "no results"
401missing_key · invalid_keyNo key, or revoked
402insufficient_creditsSays how many were needed and how many you have
404not_found · no_seriesNot in the dataset. Not charged
404movedThe path changed and the message names the new one
409ambiguousThe query matched more than one thing. Candidates are returned rather than a guess
429daily_call_capThis key's daily cap on calls that spend nothing
502upstream_unavailable · upstream_errorA government register we call did not respond, or rejected the request
500internalOur fault. Not charged
503unavailableA government register we call is down
503loadingA dataset is mid-load. Not charged, and it names what is loading
{ "error": { "code": "insufficient_credits",
             "message": "1,000 credits required for 10 rows, 200 available. Lower `limit` (max 1000)." } }

Versioning

v0 is unstable. Paths, parameters, field names and credit amounts can change without notice until v1. Pin nothing you cannot change. When a path moves, the old one answers 404 moved and names the new one rather than going silent. OpenAPI spec →

Absent fields are left out rather than returned as null. Figures are government records as of the dates shown — not estimates, and not an assessment of any company.