uks is the UrbanKit Studio command line. It lists plans, shows your key's quota and usage, resolves an
address to its county's parcel endpoint, and files a request for a county the atlas lacks. County search runs
offline against the bundled County Parcel REST API Atlas data. Every command prints one JSON document with
--json and exits with a code a script can branch on.
Node.js 22 or newer. The only runtime dependency is
@urbankitstudio/atlas, which supplies the offline data.
npx @urbankitstudio/cli --help # run once without installing
npm install -g @urbankitstudio/cli # or install the uks command
uks --helpFrom the monorepo, for development:
npm --prefix packages/cli ci
npm --prefix packages/cli exec -- tsup --config packages/cli/tsup.config.ts
node packages/cli/dist/uks.js --help| Command | Network | Key | What it does |
|---|---|---|---|
uks plans |
yes | no | Plans: price, quota, window, owner data |
uks whoami |
yes | yes | Your tier, key prefix and label, quota, subscription |
uks usage [--from D] [--to D] |
yes | yes | Calls and units in total, by endpoint, by day |
uks states |
no | no | States the atlas covers, with county and endpoint counts |
uks find <query> [--limit N] |
no | no | Counties by name, name plus state, or FIPS |
uks county <state> <county> |
no | no | One county's endpoint record (also uks county <FIPS>) |
uks lookup "<address>" [--op ID] |
yes | optional | Address to county and parcel endpoint |
uks request-county ... |
yes | no | Ask for a county the atlas lacks (free) |
uks login --key uk_live_... |
no | no | Save a key |
uks logout |
no | no | Remove the saved key |
uks plans
uks whoami --json
uks usage --from 2026-10-01 --to 2026-10-06
uks states
uks find "Kane IL"
uks county illinois kane-county
uks lookup "100 S 3rd St, Geneva, IL"
uks request-county --fips 06003 --email you@example.com
uks login --key uk_live_xxxxxxxx
uks logout
uks --version- find matches the county name exactly, then by prefix, then by substring, then by a near spelling. A
trailing state name or two-letter code narrows it ("Kane IL", "Kane County, Illinois"). A 5-digit query is
a FIPS lookup. A query that matches no county but is a state name lists that state's counties. Any miss
is a normal answer:
found: false, exit 0, and arequesthint. A name miss without a state gives arequestbody with amissinglist and placeholders in the command. - county takes the state as a slug, a name or a two-letter code, and the county as a slug (
kane-county) or a name (Kane). It prints each endpoint's service URL and layer, the owner-name column or the reason there is none, the scope predicate (scope_where) when the layer serves several counties, whether the layer takes attribute search or only spatial queries, and a link into the UrbanKit parcel lookup tool. The endpointstatusis the stamp from when the atlas package was published;live_status_urlgives the current answer. A county that is not in the atlas is a normal answer:found: false, exit 0, and therequest-countycommand that asks for it. Each endpoint also says whether the layer pages:paginationis"unsupported"on a layer that refusesresultRecordCountandresultOffset(the Mississippi statewide layers), with its per-request cap inmax_record_count. Query such a layer with one request and no paging parameters; it returns at most that many rows and setsexceededTransferLimitwhen more match, so narrow thewhereclause or the geometry instead of asking for a second page.search_notespells this out, and the human output adds aPaginationrow. - lookup works without a key at the anonymous per-IP limit. With a key, the key's quota applies and each
call counts one unit, except a call for a county we do not serve (one the atlas lacks, or one with no public
parcel endpoint) and a call that fails on our side (a 5xx answer), whose unit is credited back. A miss (
matched: false) or a county the atlas lacks (atlas_indexed: false) is a normal answer, exit 0. Each endpoint in the answer carries the samepagination,max_record_countandsearch_noteascounty, and the human output prints thePaginationrow for a layer that refuses it. For a county we do not serve, the human output prints the answer'scoverageblock: why, the county office, the county's own data product when it sells one, and therequest-countycommand. For a county that is paused (its terms or a law forbid paid use), the call is not billed and the human output prints what is paused, why, the terms it rests on, since when, the county office and the free county page. On a pay-as-you-go key, a 402 whose billing could not be confirmed prints anoperation_id(and puts it in the--jsonerror document). Retry the same address with--op '<operation_id>'within 20 hours of the original request: that retry is never billed twice, and a retry without it is billed as a new lookup. The id is bound to its address: with another address, a chargeable answer is refused and nothing is billed, and an answer that is not chargeable is returned as if no--opwere sent. - request-county names the county by
--fips 06003, or by--state <slug> --county <slug>. Slugs are strict: lowercasea-zand0-9with single hyphens (illinois,kane-county).--email,--noteand--source-url(https only) are optional. The email is used only to tell you when the county ships. Repeating the same request within 24 hours returns the first request's id. It is free, needs no key, and sends none. Limited to 5 requests per hour per IP address. - login writes the key to
~/.config/uks/credentials.json, or to$XDG_CONFIG_HOME/uks/when that is an absolute path, or to%APPDATA%\uks\credentials.jsonon Windows. On Linux and macOS the file is readable only by you (0600) and the folder is 0700. On Windows no ACL is set, so the file inherits the folder's permissions.--key -reads the key from stdin, which keeps it out of your shell history. The key is not checked against the server.uks whoamidoes that.
| Flag | Meaning |
|---|---|
--json |
Print one JSON document on stdout, errors included |
-q, --quiet |
Drop notes and hints on stderr |
--api-base <url> |
API origin, default https://urbankitstudio.com |
-h, --help |
Help for uks or for one command |
-V, --version |
CLI version and the atlas data version it carries |
uks never prints color, so NO_COLOR and a non-TTY stdout need nothing special. It refuses to send a key
over plain http to anything but a loopback address (localhost, ::1, 127.0.0.0/8).
| Variable | Meaning |
|---|---|
UKS_API_KEY |
API key; wins over the saved one |
UKS_API_BASE |
API origin, same as --api-base (the flag wins) |
XDG_CONFIG_HOME |
Where the credentials file goes on Linux and macOS, when it is an absolute path |
UKS_DEBUG |
Print a stack trace on an unexpected internal error |
| Code | Meaning |
|---|---|
| 0 | Success, including "no match" and "not in the atlas" answers |
| 1 | Refused: no key where one is needed, a key the server rejects (401/402/403), or a plan without the feature |
| 2 | Could not run: bad arguments, a network failure, a request the server rejects (other 4xx), a server error (5xx), an unreadable response |
| 3 | Rate limit, quota or county-request budget exhausted (429) |
A 429 carries one of four error strings:
error |
From | Meaning |
|---|---|---|
rate-limited |
whoami, usage, request-county |
The per-IP limit (60 per minute on the account routes, 5 per hour for county requests). Not your quota. |
rate_limited |
lookup |
The key's quota, the anonymous per-IP limit without a key, or too many rejected keys from your network (600 distinct well-formed keys in 10 minutes that matched no live key, such as revoked ones; a repeated key counts once; a malformed key never counts; refused before the key is checked, though a key accepted in the last day is still checked). |
unbilled-limit |
lookup |
Your account, all its keys together and its enrich_address calls on the hosted MCP server, made as many lookups today that charged nothing (such as addresses in counties we do not serve) as its cap: 500 on Free, 150 on Starter, 2,000 on Studio, 10,000 on Pro and pay-as-you-go. A charged call never counts, nor does an upstream outage (a 502, 503 or 504; a 500 counts), a pay-as-you-go answer for a served county from a stale cached geocode, or a pay-as-you-go 402 usage_not_recorded other than one whose op token was minted for another address or another tool. Lookups on the account pause until 00:00 UTC. Not your quota, and not billed. |
request-budget |
request-county |
The daily budget for county requests is spent. The request was not stored. |
The reset time goes to stderr and, with --json, into the error document as reset_at,
retry_after_seconds, limit and remaining. upgrade_url is present only on a lookup quota 429
(rate_limited), because only that body carries one.
- Pass
--jsonon every call. Success prints the server's document unchanged forplans,whoami,usage,lookupandrequest-county, and the CLI's own document forstates,find,county,login,logoutand--version. - An error with
--jsonprints{"ok": false, "error": "<code>", "message": "...", "exit_code": N, ...}on stdout and one line on stderr. Branch onerrorand the exit code, never onmessage. - Set
UKS_API_KEYin the environment rather than runninguks login. - Exit 3 means wait until
reset_at, or upgrade atupgrade_urlwhen it is present. - A
lookuperror carryingoperation_idis the one exit 1 worth retrying: repeat the same address with--opset to it. - Exit 2 from a network failure or a 5xx is worth one retry. Exit 2 with error "bad-arguments" is not. Fix the call. Exit 1 is not retryable.
states,findandcountynever touch the network, so they are free and work offline.
MIT. See LICENSE. © 2026 UrbanKit Studio LLC.