Item Shop API
Last updated October 27, 2026
Building with an AI agent?
Paste this into Claude Code, Cursor, Copilot or any coding agent working in your project. It tells the agent how to call the API, keep your key secret, cache answers and show the link back. Make a key first and set it as ITEMSHOP_API_KEY.
Show the prompt
Add itemshop.gg's Item Shop API to this project. Full reference: https://itemshop.gg/developers (read it if you can fetch pages).
Authentication
- Every request needs an API key, sent as the header "Authorization: Bearer <key>".
- Read the key from an environment variable named ITEMSHOP_API_KEY. Never hard-code it, commit it, or send it to a browser: call the API from server-side code only. If this project has an example env file, add ITEMSHOP_API_KEY to it with a placeholder.
- I make keys at https://itemshop.gg/account#api. If the variable isn't set, fail with a clear message saying so.
Endpoints (all GET, all JSON shaped { data, meta })
- https://itemshop.gg/api/v1/games: every game covered, with slug, name, page url, currency, reset time (UTC) and whether item history is available (itemHistory).
- https://itemshop.gg/api/v1/shop/{game}: the shop on sale now, as sections of items.
- https://itemshop.gg/api/v1/rotations: a fingerprint per game that changes when its shop changes. Poll this, and fetch a shop only when its fingerprint moves.
- https://itemshop.gg/api/v1/history/{game}: the days that game's shop changed, newest first.
- https://itemshop.gg/api/v1/history/{game}/{YYYY-MM-DD}: the shop on that day (UTC), same shape as /shop, plus shopDate and exact.
- https://itemshop.gg/api/v1/items/{game}/{itemKey}: one item and its stays in the shop. itemKey comes from items in shop or history answers.
Game slugs: valorant, marvel-rivals, overwatch, diablo-4, call-of-duty, rainbow-six-siege, aniimo, apex-legends, arc-raiders, battlefield-6, dead-by-daylight, war-thunder, pubg, once-human, league-of-legends, teamfight-tactics, path-of-exile-2, sea-of-thieves, wardogs, discord, rust.
The shop answer
- data: { game, shopDate, updatedAt, expiresAt, stale, itemCount, sections: [{ title, upcoming, endsAt, items }] }.
- Each item: { id, itemKey, name, type, rarity: { name, color } | null, price: { amount, label, currency, currencyIcon, regular }, images: { card, render }, badge, availability: { from, until, untilLabel }, bundle, contents: [...], soldOut, sourceUrl }.
- Many fields can be null; handle that. price.amount is null when the store shows no number, and price.label then holds a word such as "Included". price.currency is the game currency's name, or an ISO code like "USD" for real money. Sections with upcoming: true can't be bought yet. An empty sections list with stale: false is a genuinely empty shop.
- Write types for these shapes in this project's language.
Being a good client
- Cache answers: shops change every few minutes at most, and an answer is good for about two minutes. Send back the ETag as If-None-Match and treat 304 as "unchanged".
- The limit is 600 requests a minute per key. On 429, wait for the Retry-After header's seconds before trying again.
- Errors are { error: { code, message } }. Handle 401 (key_required or invalid_key: the key is missing, wrong or revoked), 404 (unknown_game, not_recorded, unknown_item, no_items), 429 and 503 (try again later).
- Set a User-Agent header that names this project.
Required by the terms
- Wherever the data is shown, show a visible link: "Data from itemshop.gg", linking to meta.attribution.url from the answer. Add it to the UI you build.
Start by asking me what I want built with it (for example a Discord bot command, a site widget or a daily post), unless I've already said, then implement it following the existing patterns in this codebase.Overview
The shops on itemshop.gg, and the history behind them, are available as JSON, free. Use them in a bot, an overlay, an app or your own site. Every endpoint is a GET under https://itemshop.gg/api/v1, every answer is { data, meta }, and every request needs an API key.
Getting a key
Sign in with Discord and make a key in your settings. Give the project a name, a link if it has one, and a sentence on what it does with the data: we use that to know who relies on what, and to reach you before changing anything. The key is shown once, so copy it then. You can hold 5 keys at a time and revoke any of them there.
Send the key with every request:
Authorization: Bearer isg_…
X-Api-Key: isg_… works too. Keep the key on your server: anyone who has it can use your allowance, and a key found in public code may be revoked. CORS is open, so a browser can call the API, but only do that with a key you're happy to show.
The one condition: link back
Wherever you show this data, show a visible link to itemshop.gg, ideally to the game's page (each answer's meta.attribution.url). “Data from itemshop.gg” with that link is enough. Don't resell the data or pass it off as your own. The full rules are in the terms.
GET /api/v1/games
Every game the API covers: its slug (what the other endpoints take), name, its page on itemshop.gg (url), its shop endpoint (shopUrl), its currency, and its reset. reset is an hour and minute in UTC, with a weekday (0 is Sunday) for a weekly reset and an IANA timeZone when the reset follows a place's clocks. It is null when the shop has no fixed reset and changes when its items do. historyUrl is the game's shop history, and itemHistory says whether its items have keys you can look up one by one.
{
"data": [
{
"slug": "valorant",
"name": "VALORANT",
"url": "https://itemshop.gg/valorant",
"shopUrl": "https://itemshop.gg/api/v1/shop/valorant",
"currency": {
"name": "VP",
"icon": "https://itemshop.gg/currency/vp.svg"
},
"reset": {
"hourUtc": 23,
"minuteUtc": 0,
"weekday": null,
"timeZone": null
},
"historyUrl": "https://itemshop.gg/api/v1/history/valorant",
"historyFrom": "2026-09-24",
"itemHistory": true
},
{
"slug": "once-human",
"name": "Once Human",
"url": "https://itemshop.gg/once-human",
"shopUrl": "https://itemshop.gg/api/v1/shop/once-human",
"currency": {
"name": "Crystgin",
"icon": "https://itemshop.gg/currency/crystgin.webp"
},
"reset": {
"hourUtc": 22,
"minuteUtc": 0,
"weekday": 3,
"timeZone": null
},
"historyUrl": "https://itemshop.gg/api/v1/history/once-human",
"historyFrom": null,
"itemHistory": true
},
{
"slug": "league-of-legends",
"name": "League of Legends",
"url": "https://itemshop.gg/league-of-legends",
"shopUrl": "https://itemshop.gg/api/v1/shop/league-of-legends",
"currency": {
"name": "RP",
"icon": "https://itemshop.gg/currency/rp.webp"
},
"reset": null,
"historyUrl": "https://itemshop.gg/api/v1/history/league-of-legends",
"historyFrom": null,
"itemHistory": true
}
],
"meta": {
"generatedAt": "2026-10-27T10:40:20.637Z",
"attribution": {
"text": "Data from itemshop.gg",
"url": "https://itemshop.gg"
},
"docs": "https://itemshop.gg/developers"
}
}Three of the 21 games. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/games"
GET /api/v1/shop/{game}
The game's shop as it is on sale now, in the store's own sections and order. A section marked upcoming is scheduled but can't be bought yet. This is VALORANT's answer, with a featured bundle and two of the items it also sells on their own:
{
"data": {
"game": "valorant",
"shopDate": "2026-10-27",
"updatedAt": "2026-10-27T10:00:23.248Z",
"expiresAt": "2026-11-02T19:00:00.248Z",
"stale": false,
"itemCount": 14,
"sections": [
{
"title": "Featured Bundles",
"upcoming": false,
"endsAt": null,
"items": [
{
"id": "e8f67946-03a5-4b6a-b2ff-7f4bfe77f454",
"itemKey": "va:bundle:f67ab55a4480f30598919bac1b17459f",
"name": "Popmonz",
"type": "Bundle · 8 items",
"rarity": {
"name": "Bundle",
"color": "#FF4655"
},
"price": {
"amount": 8700,
"label": null,
"currency": "VP",
"currencyIcon": "https://itemshop.gg/currency/vp.svg",
"regular": null
},
"images": {
"card": "https://itemshop.gg/api/valorant/panel/f67ab55a-4480-f305-9891-9bac1b17459f.png",
"render": null
},
"badge": "39% off",
"availability": {
"from": null,
"until": "2026-11-11T00:00:00.248Z",
"untilLabel": null
},
"bundle": null,
"contents": [
{
"name": "Popmonz Knife",
"type": "Weapon skin",
"rarity": null,
"image": "https://cdn.source.gs/valorant/img/popmonz-knife-3c7ff0-512.webp",
"quantity": 1,
"itemKey": "va:item:88e0e23d46ebe8464fdccda690576c0a"
},
{
"name": "Popmonz Phantom",
"type": "Weapon skin",
"rarity": null,
"image": "https://cdn.source.gs/valorant/img/popmonz-phantom-3a476e-512.webp",
"quantity": 1,
"itemKey": "va:item:06264cd64b3262d69fb0458f960f314b"
}
],
"soldOut": false,
"sourceUrl": "https://valorant.gs/bundles/#popmonz"
}
]
},
{
"title": "Popmonz",
"upcoming": false,
"endsAt": "2026-11-11T00:00:00.248Z",
"items": [
{
"id": "e8f67946-03a5-4b6a-b2ff-7f4bfe77f454-88e0e23d-46eb-e846-4fdc-cda690576c0a",
"itemKey": "va:item:88e0e23d46ebe8464fdccda690576c0a",
"name": "Popmonz Knife",
"type": "Weapon skin",
"rarity": {
"name": "Exclusive",
"color": "#f5955b"
},
"price": {
"amount": null,
"label": "Included",
"currency": "VP",
"currencyIcon": "https://itemshop.gg/currency/vp.svg",
"regular": null
},
"images": {
"card": "https://cdn.source.gs/valorant/img/popmonz-knife-3c7ff0-512.webp",
"render": null
},
"badge": "Bundle only",
"availability": {
"from": null,
"until": null,
"untilLabel": null
},
"bundle": "Popmonz",
"contents": [],
"soldOut": false,
"sourceUrl": "https://valorant.gs/skins/popmonz-knife/"
},
{
"id": "e8f67946-03a5-4b6a-b2ff-7f4bfe77f454-06264cd6-4b32-62d6-9fb0-458f960f314b",
"itemKey": "va:item:06264cd64b3262d69fb0458f960f314b",
"name": "Popmonz Phantom",
"type": "Weapon skin",
"rarity": {
"name": "Exclusive",
"color": "#f5955b"
},
"price": {
"amount": 2175,
"label": null,
"currency": "VP",
"currencyIcon": "https://itemshop.gg/currency/vp.svg",
"regular": null
},
"images": {
"card": "https://cdn.source.gs/valorant/img/popmonz-phantom-3a476e-512.webp",
"render": null
},
"badge": null,
"availability": {
"from": null,
"until": null,
"untilLabel": null
},
"bundle": "Popmonz",
"contents": [],
"soldOut": false,
"sourceUrl": "https://valorant.gs/skins/popmonz-phantom/"
}
]
}
]
},
"meta": {
"generatedAt": "2026-10-27T10:40:20.742Z",
"attribution": {
"text": "Data from itemshop.gg",
"url": "https://itemshop.gg/valorant"
},
"docs": "https://itemshop.gg/developers"
}
}Trimmed from a real answer: 3 of its 14 items and 2 of the bundle's 8 contents. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/shop/valorant"
Every game has the same shape. Two items from League of Legends: a skin on sale, with its regular price and when the sale ends, and a Mythic Shop item priced in the game's second currency:
[
{
"id": "item:skin:67067",
"itemKey": "lol:item:skin:67067",
"name": "Demoncursed Vayne",
"type": "Vayne",
"rarity": {
"name": "Legendary",
"color": "#e5484d"
},
"price": {
"amount": 1350,
"label": null,
"currency": "RP",
"currencyIcon": "https://itemshop.gg/currency/rp.webp",
"regular": 1820
},
"images": {
"card": "https://cdn.source.gs/league-of-legends/img/skin-67067-tile-a8fa5c71.webp",
"render": null
},
"badge": "26% off",
"availability": {
"from": "2026-10-26T17:00:00Z",
"until": "2026-11-02T18:00:00Z",
"untilLabel": "Sale ends"
},
"bundle": null,
"contents": [],
"soldOut": false,
"sourceUrl": "https://lol.source.gs/skins/demoncursed-vayne/"
},
{
"id": "item:skin:235009",
"itemKey": "lol:item:skin:235009",
"name": "Prestige True Damage Senna",
"type": "Senna",
"rarity": {
"name": "Mythic",
"color": "#b66dff"
},
"price": {
"amount": 150,
"label": null,
"currency": "Mythic Essence",
"currencyIcon": "https://itemshop.gg/currency/mythic-essence.webp",
"regular": null
},
"images": {
"card": "https://cdn.source.gs/league-of-legends/img/skin-235009-tile-313e1481.webp",
"render": null
},
"badge": "New",
"availability": {
"from": "2026-10-21T18:00:00Z",
"until": "2026-11-18T19:00:00Z",
"untilLabel": null
},
"bundle": null,
"contents": [],
"soldOut": false,
"sourceUrl": "https://lol.source.gs/skins/prestige-true-damage-senna/"
}
]2 of 128 items. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/shop/league-of-legends"
Item fields
| Field | Type | Meaning |
|---|---|---|
| id | string | This listing. It can be new when an item comes back, and an item listed in two sections has the same id in both. |
| itemKey | string | null | The item itself, the same every time it is sold: use it to follow an item across shops. Null for games and listings without one. |
| name | string | As the store names it. |
| type | string | null | What it is, as the store says (“Weapon skin”, “Bundle · 8 items”, a champion's name). Null when the store says nothing. |
| rarity | { name, color } | null | The store's tier or edition and its colour. Null for games or items without one. |
| price.amount | number | null | What it costs. Null when the store shows no number. |
| price.label | string | null | A word the store shows instead of a price (“Included”, “Free”). Only set when amount is null. |
| price.currency | string | The game currency's name (“VP”, “Mythic Essence”), or an ISO 4217 code (“USD”) for a real-money price. |
| price.currencyIcon | string | null | The game currency's icon. Null for real money. |
| price.regular | number | null | The price before a discount, when it is discounted. |
| images.card | string | null | The store's art for it. Null for the few items the source has no picture of yet. |
| images.render | string | null | The item's own cut-out render, when the source has one. |
| badge | string | null | The store's tag: “New”, “Last day”, “30% off”, “Bundle only”. |
| availability.from / until | string | null | When it went on sale and when it leaves, as ISO times, when the source says. |
| availability.untilLabel | string | null | What happens at until when the item stays (“Sale ends”). Null means it leaves. |
| bundle | string | null | The bundle it comes in, when bundle items are listed on their own (VALORANT). |
| contents | array | A bundle's items: name, type, rarity, image, quantity, itemKey. Empty when there are none or the source doesn't list them. |
| soldOut | boolean | Listed but sold out (a Gran Turismo dealership car). |
| sourceUrl | string | null | The item's page at its source, when there is one. |
The shop
shopDateis the rotation's day.updatedAtis when the store was last read, andexpiresAtis the next scheduled change, when one is known.stale: truemeans the source couldn't be read just now and this is the last good copy.- An empty
sectionslist withstale: falseis a real empty shop (VALORANT between bundles). - Images are full-size originals. Game art belongs to its publisher: show it to identify the item, as this site does.
GET /api/v1/rotations
A fingerprint per game that changes whenever the shop does, with changedAt, when it last changed. It is the cheap way to watch every shop: poll this once a minute and fetch a shop only when its fingerprint moves.
{
"data": {
"valorant": {
"fingerprint": "487f459b8d304092b552376a7e2689164f76dfc1",
"changedAt": "2026-10-20T23:01:30.500Z"
},
"league-of-legends": {
"fingerprint": "a1b813dcf409d28e387d5757f8ccbc1afce472d3",
"changedAt": "2026-10-27T00:16:39.235Z"
}
},
"meta": {
"generatedAt": "2026-10-27T10:40:20.620Z",
"attribution": {
"text": "Data from itemshop.gg",
"url": "https://itemshop.gg"
},
"docs": "https://itemshop.gg/developers"
}
}Two of the games. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/rotations"
GET /api/v1/history/{game}
Every day the game's shop changed, newest first, as far back as our record goes. The record is the one itemshop.gg keeps itself, so it starts when we began reading that shop; historyFrom in /games says where it starts when that is later than the site's own pages go.
{
"data": [
"2026-10-27",
"2026-10-26",
"2026-10-25"
],
"meta": {
"generatedAt": "2026-10-27T10:40:20.650Z",
"attribution": {
"text": "Data from itemshop.gg",
"url": "https://itemshop.gg/valorant"
},
"docs": "https://itemshop.gg/developers"
}
}The three newest days. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/history/valorant"
GET /api/v1/history/{game}/{date}
The shop as it stood on a day (YYYY-MM-DD, UTC), in the same shape as /shop. When the shop didn't change that day, you get the last version before it: shopDate says which day that was and exact is false. A day before the record starts is 404 not_recorded.
{
"data": {
"date": "2026-10-27",
"shopDate": "2026-10-27",
"exact": true,
"shop": {
"game": "league-of-legends",
"shopDate": "2026-10-27",
"updatedAt": "2026-10-27T00:05:40Z",
"expiresAt": "2026-10-28T00:00:00.000Z",
"stale": false,
"itemCount": 128,
"sections": [
{
"title": "Skin sale this week",
"upcoming": false,
"endsAt": null,
"items": [
{
"id": "item:skin:67067",
"itemKey": "lol:item:skin:67067",
"name": "Demoncursed Vayne",
"type": "Vayne",
"rarity": {
"name": "Legendary",
"color": "#e5484d"
},
"price": {
"amount": 1350,
"label": null,
"currency": "RP",
"currencyIcon": "https://itemshop.gg/currency/rp.webp",
"regular": 1820
},
"images": {
"card": "https://cdn.source.gs/league-of-legends/img/skin-67067-tile-a8fa5c71.webp",
"render": null
},
"badge": "26% off",
"availability": {
"from": "2026-10-26T17:00:00Z",
"until": "2026-11-02T18:00:00Z",
"untilLabel": "Sale ends"
},
"bundle": null,
"contents": [],
"soldOut": false,
"sourceUrl": "https://lol.source.gs/skins/demoncursed-vayne/"
}
]
}
]
}
},
"meta": {
"generatedAt": "2026-10-27T10:40:20.654Z",
"attribution": {
"text": "Data from itemshop.gg",
"url": "https://itemshop.gg/league-of-legends"
},
"docs": "https://itemshop.gg/developers"
}
}Trimmed to 1 of its 128 items. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/history/league-of-legends/2026-10-27"
GET /api/v1/items/{game}/{itemKey}
One item, in the shop's item shape, and every stay it has had in the shop, newest first. The itemKey is the one on the item in a shop or history answer; games with itemHistory: false answer 404 no_items. A stay's end is null while it is still on sale, state is past, now or upcoming, and its currency is named only when it isn't the game's main one.
{
"data": {
"item": {
"id": "cat:item:skin:67067",
"itemKey": "lol:item:skin:67067",
"name": "Demoncursed Vayne",
"type": "Skin · Vayne",
"rarity": {
"name": "Legendary",
"color": "#e5484d"
},
"price": {
"amount": 1350,
"label": null,
"currency": "RP",
"currencyIcon": "https://itemshop.gg/currency/rp.webp",
"regular": null
},
"images": {
"card": "https://cdn.source.gs/league-of-legends/img/skin-67067-tile-a8fa5c71.webp",
"render": "https://cdn.source.gs/league-of-legends/img/skin-67067-tile-a8fa5c71.webp"
},
"badge": null,
"availability": {
"from": null,
"until": null,
"untilLabel": null
},
"bundle": null,
"contents": [],
"soldOut": false,
"sourceUrl": "https://lol.source.gs/skins/demoncursed-vayne/"
},
"stays": [
{
"start": "2026-10-26T17:00:00Z",
"end": "2026-11-02T18:00:00Z",
"shop": null,
"price": 1350,
"currency": null,
"state": "now",
"days": 1
}
]
},
"meta": {
"generatedAt": "2026-10-27T10:40:21.376Z",
"attribution": {
"text": "Data from itemshop.gg",
"url": "https://itemshop.gg/league-of-legends"
},
"docs": "https://itemshop.gg/developers"
}
}The whole answer. The live answer:
curl -H "Authorization: Bearer $ITEMSHOP_KEY" \ "https://itemshop.gg/api/v1/items/league-of-legends/lol:item:skin:67067"
Freshness, caching and limits
- Shops are read every few minutes. A shop answer is reused for two minutes, so polling faster gains nothing.
- Every answer has an
ETag. Send it back asIf-None-Matchand you get an empty304until something changes. Answers may be cached by you, not by a shared cache. - Up to 600 requests a minute per key (the
X-RateLimit-Limitheader). Past that you get429with aRetry-Afterheader. Need more? Get in touch. - Errors are
{ error: { code, message } }:401 key_required,401 invalid_key,404 unknown_game,404 not_recorded,404 unknown_item,429 rate_limited,503 shop_unavailable.
Versioning
Everything under /api/v1 only grows: fields and games are added, never renamed or removed. Anything that has to break will come as /api/v2, with v1 kept running for at least three months and the change announced on our Discord.
Games covered
- VALORANT shop API
valorant - Marvel Rivals shop API
marvel-rivals - Overwatch shop API
overwatch - Diablo 4 shop API
diablo-4 - Call of Duty shop API
call-of-duty - Rainbow Six Siege shop API
rainbow-six-siege - Aniimo shop API
aniimo - Apex Legends shop API
apex-legends - ARC Raiders shop API
arc-raiders - Battlefield 6 shop API
battlefield-6 - Dead by Daylight shop API
dead-by-daylight - War Thunder shop API
war-thunder - PUBG: Battlegrounds shop API
pubg - Once Human shop API
once-human - League of Legends shop API
league-of-legends - Teamfight Tactics shop API
teamfight-tactics - Path of Exile 2 shop API
path-of-exile-2 - Sea of Thieves shop API
sea-of-thieves - WARDOGS shop API
wardogs - Discord shop API
discord - Rust shop API
rust
Other games aren't supported yet.
Contact and support
Questions, bugs or something you'd like the API to do? Ask on our Discord at discord.gg/itemshops, where API changes are announced too. Building something, or need more than the limits allow? Email [email protected].