Skip to content
Volume72,986,084.24all timeupdated

API documentation

A read-only JSON view of the same market mirror the site renders.

Getting a key

Keys are granted by hand, free, to people building something. Sign in to GnomeStats with Discord once (the grant attaches to an existing account), then ask in the GnomeCorp Discord or message GnomeWhisperer in game with a line about what you are building. There is no self-serve signup and no payment. Keys are read-only: the API exposes the public market mirror and nothing else, moves no money, and holds no balances.

Send the token as a bearer header on every request:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://www.gnomestats.com/api/v1/items?sort=spread&pageSize=10"

Scopes

Every key carries one or more of three read-only scopes.

market:readRead the global market overview and stats series.
items:readRead item screener rows, item detail, history, and movers.
shops:readRead shop listings and per-shop change history.

Endpoints

Seven endpoints, all GET, all JSON. The public param names and value grammars are frozen: values may be added (a new sort key, a new alert semantics note below), names never change.

GET /api/v1/itemsitems:read

?sort=totalVolume|tradeCount|minBuyPrice|maxSellPrice|activeShopCount|spread|change &dir=asc|desc &page=1 &pageSize=50 &window=7|30|90|365|all &material=STONE &custom=true|false &inStock=true

The screener: one row per item with registry price signals and change%.

GET /api/v1/items/:itemKeyitems:read

?window=7|30|90|365|all

One item's page data: aggregates, detail header, daily history. 404 on an unknown key.

GET /api/v1/items/:itemKey/historyitems:read

?window=7|30|90|365|all

The per-day accrual rows, oldest first: sales, quantity, dollar volume, blended average.

GET /api/v1/moversitems:read

?kind=gainers|losers|volatile|liquidity &window=7|30|90|365|all

Movers boards. accrued:false with empty lists when the window outruns history.

GET /api/v1/shopsshops:read

?item=<itemKey> &buyable=true &inStock=true &sort=buyPrice|sellPrice|stock, or without ?item: &material &firm &page &pageSize

Item-scoped registry rows, or the paged shop directory.

GET /api/v1/shops/:shopId/historyshops:read

The shop's change series, oldest first: price, stock, listed, delisted. 400 on a non-numeric id.

GET /api/v1/market/overviewmarket:read

?window=7|30|90|365|all

Global totals plus a date-bucketed series at adaptive resolution.

Rate limits

Each key has a per-minute request budget, 120 by default (yours may differ). Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; a 429 adds Retry-After. The headers are the authoritative statement of your budget, so read them rather than hard coding a number. Unauthenticated requests share a small per-address budget that exists only to answer with clean errors.

Errors

codestatusmeaning
MISSING_TOKEN401No Authorization: Bearer header.
INVALID_TOKEN401The token matches no key.
TOKEN_EXPIRED401The key's expiry has passed.
TOKEN_REVOKED401The key was revoked by an admin.
FORBIDDEN403The key lacks the route's scope.
RATE_LIMITED429Budget exhausted; honour Retry-After.
NOT_FOUND404Unknown item or shop.
INTERNAL500Request failed on our side; retry later.

Every error body has one shape: {"error":{"code":"...","message":"..."}}.

Reading the numbers honestly

The caveats the site prints beside its own figures apply to yours too. Money values serialize as exact decimal strings, never floats, and big counters as strings where they can pass 2^53; parse accordingly. A buyPrice of 0.00 is a disabled side of the sign, not a free item. avgUnitPrice in the history rows is a buy plus sell blended, unit-weighted average: a liquidity signal, not a clean price. The day field is an opaque YYYY-MM-DD string on the economy server's clock; compare lexicographically and never convert it through a timezone. Registry figures trail the live game by up to a crawl cycle, about two hours for shop stock, and the freshness section carries the full cadence table.

Semantics changes are announced here and in the route headers. 2026-07-17: maxSellPrice everywhere now also excludes passed-over sell listings (payouts the market routed around for a week); values can only tighten, no shape change.