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 call | A fixed amount for one thing — a company record, an employment series, one address |
|---|---|
| Per row | Charged for rows returned, never for the call.
limit is what controls the bill |
| Free | 0 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
| Status | Code | Means |
|---|---|---|
| 400 | bad_query · bad_cursor · missing_query · query_too_long | A filter value or cursor we do not accept. The message names what is accepted — a typo should not look like "no results" |
| 401 | missing_key · invalid_key | No key, or revoked |
| 402 | insufficient_credits | Says how many were needed and how many you have |
| 404 | not_found · no_series | Not in the dataset. Not charged |
| 404 | moved | The path changed and the message names the new one |
| 409 | ambiguous | The query matched more than one thing. Candidates are returned rather than a guess |
| 429 | daily_call_cap | This key's daily cap on calls that spend nothing |
| 502 | upstream_unavailable · upstream_error | A government register we call did not respond, or rejected the request |
| 500 | internal | Our fault. Not charged |
| 503 | unavailable | A government register we call is down |
| 503 | loading | A 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.