← Hardcore Market Tools · Interactive docs
Hardcore World Tool Kit - data API
Read-only access to the market data collected by the RuneLite plugin "Hardcore World Tool Kit" on the Hardcore Worlds.
Data from this service must not be used for real-world trading. It is a community tool for the game's Grand Exchange, provided as is.
The basics
- Open to everyone: no key, no account, no sign-up. Plain
GETrequests; the answers are JSON. - Any website may call it from a browser (CORS is open for reads). Nothing can be written through it: uploads need a key that only the plugin holds.
- Times are Unix seconds (UTC). Prices and totals are in gp.
- The data comes from players using the plugin, so an item nobody traded has no prices. Names, ids and accounts of the players are never in the data: a trade is only an item, a side, a price, a quantity and a time.
- Answers are shared and kept for up to a minute, so asking more often than that gets you the same data. A client that asks far too often may be refused (HTTP 429 or 503).
- Errors come as
{"error": "..."}with a status: 400 for a bad parameter, 404 for an unknown path or item, 429 or 503 when you or the server are too busy (503 carriesRetry-After). - Fields may be added over time. Ignore the ones you don't know.
curl https://HOST/v1/items?ids=2,4151
Replace HOST with this page's address.
GET /v1/items
Every item with trades or open offers: the prices of the last 24 hours and the current offers.
| Parameter | Meaning |
|---|---|
ids | Optional. Up to 100 comma-separated item ids (?ids=2,4151). Without it, every item. |
world | Optional. Not needed: this service always answers for the Hardcore Worlds, which share one economy (shown as world 9000), whatever you pass. |
include | Optional extras, comma-separated: fill (the last price of live trades only, as lastFillBuy,
lastFillSell and their ...Time), trust (a reference price trustedPrice with trustedVotes and trustedPriceTime,
the trusted best bid and ask, and how much of the volume was confirmed by two sides: confVol24 and unconfVol24). |
{ "time": 1793735269, "world": null,
"items": [ { "id": 4151, "name": "Abyssal whip", "hasIcon": true,
"vol24": 12, "gp24": 3100000, "reporters24": 3, "avgBuy24": 258000, "avgSell24": 259000,
"lastBuy": 258000, "lastBuyTime": 1793734000, "lastSell": 259000, "lastSellTime": 1793733000,
"bids": 2, "asks": 4, "bestBid": 255000, "bestAsk": 262000, "bidQty": 3, "askQty": 9 } ] }
| Field | Meaning |
|---|---|
vol24, gp24 | Units traded and gp traded in the last 24 hours. |
reporters24 | How many different players' plugins reported these trades. A price from 1 reporter is weaker than one from 10. |
avgBuy24, avgSell24 | Average price (weighted by quantity) of the buys and of the sells in the last 24 hours. Missing when there were none. |
lastBuy, lastSell (+ Time) | The last known price on each side and when it happened. Missing when never seen. |
bids, asks, bestBid, bestAsk, bidQty, askQty | The open offers players have in the Grand Exchange (the number of offers, the highest buy and lowest sell price, the quantity wanted and for sale). Offers not refreshed for 14 days are ignored. |
GET /v1/item/{id}
One item: a summary, its latest trades and its order book.
| Parameter | Meaning |
|---|---|
limit | Optional. Trades to return, 1 to 500 (default 100). |
before | Optional. A cursor for older trades: pass the nextBefore of the previous answer. |
world, include | As above. |
{ "id": 4151, "name": "Abyssal whip", "hasIcon": true,
"summary": { "lastBuy": 258000, "lastBuyTime": 1793734000, "lastSell": 259000, "lastSellTime": 1793733000,
"vol24": 12, "avgBuy24": 258000, "avgSell24": 259000, "bestBid": 255000, "bestAsk": 262000 },
"trades": [ { "kind": "fill", "side": "buy", "qty": 1, "price": 258000, "total": 258000,
"ts": 1793734000, "late": false, "world": 9000 } ],
"book": { "bids": [ { "price": 255000, "offers": 1, "qty": 2, "oldest": 1793700000 } ],
"asks": [ { "price": 262000, "offers": 2, "qty": 5, "oldest": 1793690000 } ] },
"nextBefore": "1793733000_15123" }
trades[].kind:fillis a trade seen as it happened;historywas read later from the game's Grand Exchange History tab (solateis true and the time is approximate);cancelledis an offer that was cancelled.sideisbuyorsell.book: open offers grouped by price.oldestis when the oldest offer at that price was placed. Bids are listed highest first, asks lowest first.nextBeforeisnullwhen there are no older trades.
GET /v1/item/{id}/series
The price history of one item, as averages per time bucket (for a chart).
| Parameter | Meaning |
|---|---|
range | Optional: 24h, 7d, 30d, 90d or 1y. Each has a default step (5 minutes, 1 hour, 6 hours, 6 hours, 1 day). |
step | Optional bucket size: 5m, 1h, 6h or 24h. Without range, the last 365 buckets of that size (default 1h). With one, it is used unless it would give more than 2016 buckets. |
world, include | As above (include=trust adds the confirmed-trade averages and volumes). |
{ "id": 4151, "step": "1h", "range": "7d",
"data": [ { "timestamp": 1793732400, "avgBuy": 258000, "avgSell": 259000, "buyVolume": 2, "sellVolume": 1 } ] }
timestamp is the start of the bucket. A bucket without trades on one side has null for that average. Buckets with no trades at all are left out.
GET /v1/recent
The live feed of events (trades and offers), newest first, with the totals of the last 24 hours.
| Parameter | Meaning |
|---|---|
limit | Optional. 1 to 200 events (default 50). |
kinds | Optional filter, comma-separated: placed, fill, cancelled, history. The stats are not filtered. |
after | Optional. An event id: only events newer than it. Keep the newest id you have seen and pass it next time to receive only what is new. |
before | Optional. An event id: only events older than it (for paging back). |
world | As above. |
{ "time": 1793735270,
"stats": { "events24": 666, "reporters24": 26, "units24": 196586, "gp24": 119488147,
"openBids": 41, "openAsks": 97, "tradersWithOffers": 39 },
"events": [ { "id": 15126, "kind": "placed", "side": "buy", "itemId": 22552, "name": "Thammaron's sceptre (u)",
"hasIcon": true, "qty": 1, "price": 10000000, "total": null,
"ts": 1793734311, "late": false, "receivedAt": 1793734320 } ] }
placed is an offer put into the Grand Exchange (its total is null: nothing traded yet); fill is a trade.
receivedAt is when the server got it, rounded down to the minute. reporters24 counts the plugins that reported anything in the last 24 hours.
GET /v1/icon/{id}
The item's icon as a PNG (answers 404 when there is none; hasIcon in the other answers says whether there is one). Cached by browsers for a day.
GET /v1/health
{"ok": true, "time": 1793735270}, or status 503 with "ok": false when the database can't be reached.
Privacy
This API publishes prices, quantities and times only. How the data is collected, which identifiers the server keeps and for how long is in the privacy notice.
Questions or problems: Discord @Novith.