Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

steamworks-api-simplified

The Steam API guide we wish existed.

A practical guide to the Steamworks Web API covering sales data, wishlist reporting, reviews, player counts, achievements and partner endpoints. Focused on real-world usage, common pitfalls and clear examples for game developers.

🌍 Türkçe · Deutsch


You shipped your game on Steam. Congrats! Now you need data: how many people are playing, what are they saying in reviews, how are sales going, where are your wishlists coming from.

You open Steam's official API docs and... it's a maze. Three different key types. Two different API hosts. Some endpoints need a key, some don't. Date formats change between endpoints. Financial data comes back as strings instead of numbers. The docs assume you already know everything.

We've been there. This guide is everything we learned, organized the way we wish someone had explained it to us.


Table of Contents


New to APIs? Start here

If you've only ever worked in a game engine and never called a web API before, no worries. It's simpler than it sounds.

An API is just a URL. You visit the URL, and instead of a web page, you get back raw data (usually JSON, basically structured text).

Try it right now. Copy this URL and paste it into your browser:

https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=3349960

You'll see something like:

{ "response": { "player_count": 42, "result": 1 } }

That's it. You just called the Steam API. That URL returns the number of people currently playing okey.gg (a tile game by yilmaz.games, hi, that's us 👋).

In your code, you'd do the same thing: fetch a URL and read the response. Here's what that looks like:

// JavaScript / Node.js
const response = await fetch(
  "https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=YOUR_APP_ID"
);
const data = await response.json();
console.log(data.response.player_count); // 42
# Python
import requests

response = requests.get(
    "https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/",
    params={"appid": "YOUR_APP_ID"}
)
data = response.json()
print(data["response"]["player_count"])  # 42
// C# / Unity
using var client = new HttpClient();
var response = await client.GetStringAsync(
    "https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=YOUR_APP_ID"
);
// Parse the JSON string to get player_count
# GDScript / Godot
var http = HTTPRequest.new()
add_child(http)
http.request("https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=YOUR_APP_ID")
# Connect to request_completed signal to handle the response

Useful tools for exploring APIs:

  • Your browser (seriously, just paste URLs)
  • Postman or Insomnia, free apps that make it easy to build and test API calls
  • curl in your terminal: curl "https://api.steampowered.com/..."

Now you're ready for the rest of this guide. Every endpoint below works the same way: it's a URL, you call it, you get data back.


Quick Start: Which Key Do I Need?

Before diving into endpoints, here's what you need for each type of data:

Data you want Key type Where to call
Current online players No key needed api.steampowered.com
App details, pricing No key needed store.steampowered.com
Reviews No key needed store.steampowered.com
News No key needed api.steampowered.com
Achievement percentages No key needed api.steampowered.com
Sales & revenue Financial key or Publisher key (with Sales Data perm) partner.steam-api.com
Wishlist data Financial key or Publisher key (with Sales Data perm) partner.steam-api.com
Game stats (if defined) Publisher key partner.steam-api.com
Leaderboards (if defined) Publisher key partner.steam-api.com
Microtransaction reports Publisher key (with Microtransaction perm) partner.steam-api.com
Banned players Publisher key partner.steam-api.com

Notice the pattern: Free/public data → api.steampowered.com (no key). Your private business data → partner.steam-api.com (key required). Using the wrong host is the #1 most common mistake.


The Three Types of Steam API Keys

Steam has three different API keys. Yes, three. Here's what each one does and how to get it.

1. Web API Key

The basic key anyone with a Steam account can get. You probably don't even need this one. Most public endpoints work without any key at all.

How to get it:

  1. Go to https://steamcommunity.com/dev/apikey
  2. Log in with your Steam account
  3. Enter a domain name and register
  4. Copy your key

What it can do: Access public endpoints on api.steampowered.com. Useful for user-specific lookups (player profiles, friend lists, etc.).

What it can't do: Access any partner or publisher endpoints. No sales data, no wishlist data, nothing on partner.steam-api.com.

2. Publisher Web API Key

A key tied to a group of apps in your Steamworks partner account. This is the most flexible key type. You choose exactly which permissions it has.

How to get it:

  1. Log in to https://partner.steamgames.com
  2. Go to Users & PermissionsManage Groups
  3. Select an existing group or create a new one
  4. Assign your apps to the group (if they're not already there)
  5. Click "Create WebAPI Key" on the group page
  6. Select which permissions to enable:
    • Microtransactions: transaction reports and management
    • Sales Data: sales, revenue, and wishlist data (IPartnerFinancialsService)
    • Economy: Steam Inventory Service
    • General API: authentication, DLC ownership checks
  7. Optionally configure IP whitelisting (see gotchas if you're on serverless)

What it can do: Everything the Web API key does, plus partner endpoints on partner.steam-api.com. But only for apps in its group, and only with the permissions you enabled.

⚠️ Want sales/wishlist data? You must enable the "Sales Data" permission when creating the key. Without it, you'll get empty responses with no error message, just {}. This is a very common trap.

3. Financial API Key

A special-purpose key for financial data only. Gives you unrestricted access to sales and wishlist data across ALL your apps.

How to get it:

  1. Log in to https://partner.steamgames.com
  2. Go to Users & PermissionsManage Groups
  3. Click "Create new group" and select "Financial API Group"
  4. The key appears on the group page immediately

What it can do: Access IPartnerFinancialsService endpoints (sales, wishlists) for every app on your partner account, no per-app restrictions.

How it differs from the publisher key: A Financial API Group has no users and no apps assigned to it. It exists purely as a financial data access key. A publisher key with "Sales Data" permission can access the same endpoints, but only for apps in its specific group.

When to use which:

  • One game? Publisher key with "Sales Data" permission is fine.
  • Multiple games across different groups? Financial key is simpler. One key for all financial data.

API Hosts

Steam has two separate API servers. Using the wrong one is the single most common mistake.

Host Who can use it Protocol Key required?
api.steampowered.com Anyone HTTP or HTTPS Usually no
partner.steam-api.com Publisher/Financial keys only HTTPS only Always

Rule of thumb: If you're looking at public game data (player counts, reviews, news), use api.steampowered.com. If you're looking at your own business data (sales, wishlists, ownership), use partner.steam-api.com.

If you need to whitelist partner API IPs (e.g., for a corporate firewall):

  • 208.64.200.0/22
  • 155.133.239.0/24

Endpoints: Public Data (No Key Required)

These endpoints are open to everyone. No API key needed. You can test them in your browser right now.

Current Online Players

GET https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid={appid}

Returns the number of players currently in-game.

{ "response": { "player_count": 42, "result": 1 } }

💡 Try it: Paste this in your browser → https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=3349960. That's the live player count for okey.gg. Replace 3349960 with your own App ID.

App Details (Store API)

GET https://store.steampowered.com/api/appdetails?appids={appid}

Returns everything on the store page: name, description, pricing, screenshots, system requirements, release date, genres, categories, developers, publishers.

For pricing in a specific region, add &cc={country_code}:

GET https://store.steampowered.com/api/appdetails?appids={appid}&cc=us
GET https://store.steampowered.com/api/appdetails?appids={appid}&cc=de
GET https://store.steampowered.com/api/appdetails?appids={appid}&cc=tr
GET https://store.steampowered.com/api/appdetails?appids={appid}&cc=cn

The price_overview object contains:

  • currency: e.g., "USD", "EUR", "TRY"
  • initial: base price in cents (e.g., 999 = $9.99)
  • final: current price in cents (after any discount)
  • discount_percent: active discount percentage

⚠️ Rate limit: ~200 requests per 5 minutes. Cache aggressively. Store page data doesn't change often.

Reviews

GET https://store.steampowered.com/appreviews/{appid}?json=1&filter=recent&language=all&num_per_page=100

Parameters:

Parameter Values Description
filter recent, updated, all Sort order
language all or language code Filter by language
num_per_page 1–100 Results per page
cursor * (first page), then value from response Pagination
review_type all, positive, negative Filter by sentiment
purchase_type all, steam, non_steam_purchase Filter by purchase source

Response includes:

  • query_summary: total_positive, total_negative, total_reviews, review_score, review_score_desc
  • reviews[]: individual reviews with author info, playtime, language, text, voted_up, timestamp, helpfulness votes

News

GET https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?appid={appid}&count=10
Parameter Default Description
count 20 Number of articles to return
maxlength full Truncate content (0 = full text)
feeds all Comma-separated feed names to filter

Achievement Percentages

GET https://api.steampowered.com/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v2/?gameid={appid}

Returns global unlock percentages for each achievement. Useful for balancing achievement difficulty or showing community stats.

Game Schema (Stats & Achievements List)

GET https://api.steampowered.com/ISteamUserStats/GetSchemaForGame/v2/?appid={appid}&key={webApiKey}

Returns all stats and achievements defined for the game, with display names and descriptions. You'll need this to discover stat names before calling GetGlobalStatsForGame.

Note: This is the one public-ish endpoint that benefits from having a Web API key.


Endpoints: Sales & Revenue (Financial/Publisher Key)

All endpoints below use partner.steam-api.com and require either a Financial key or a Publisher key with "Sales Data" permission enabled.

🔒 Important: These calls must be made from a server. Never expose your publisher or financial key in client-side code, game builds, or public repositories.

GetDetailedSales

GET https://partner.steam-api.com/IPartnerFinancialsService/GetDetailedSales/v001/
    ?key={key}
    &date={YYYY-MM-DD}
    &highwatermark_id=0

Returns all sales across all your apps for a single date. There is no per-app endpoint. You filter by primary_appid in your code.

Parameters:

Parameter Required Description
key Yes Your financial or publisher key
date Yes YYYY-MM-DD, interpreted as Pacific Time (not UTC!)
highwatermark_id Yes Start at 0. If more data exists, response includes max_id. Use it to paginate

Response example:

{
  "response": {
    "results": [
      {
        "date": "2026-04-03",
        "line_item_type": "Package",
        "packageid": 1234567,
        "package_sale_type": "Steam",
        "platform": "Windows",
        "country_code": "US",
        "base_price": "999",
        "sale_price": "999",
        "currency": "USD",
        "gross_units_sold": 1,
        "gross_units_returned": 0,
        "gross_sales_usd": "9.9900",
        "gross_returns_usd": "0.0000",
        "net_tax_usd": "0.0000",
        "primary_appid": 1234567,
        "net_units_sold": 1,
        "net_sales_usd": "9.9900"
      }
    ],
    "package_info": ["..."],
    "app_info": ["..."],
    "country_info": ["..."],
    "partner_info": ["..."],
    "max_id": "29557611440"
  }
}

Each line item is a sale or refund, broken down by date, country, platform, and package.

⚠️ Gotcha: Notice that gross_sales_usd, net_sales_usd, etc. are strings, not numbers. You must convert them: parseFloat(item.gross_sales_usd) in JavaScript, float(item["gross_sales_usd"]) in Python.

GetAppWishlistReporting

GET https://partner.steam-api.com/IPartnerFinancialsService/GetAppWishlistReporting/v001/
    ?key={key}
    &appid={appid}
    &date={YYYY-MM-DD}

Returns wishlist activity for a specific app on a specific date.

Parameters:

Parameter Required Description
key Yes Your financial or publisher key
appid Yes Your game's App ID
date Yes YYYY-MM-DD, in GMT (not Pacific Time, yes, it's different from sales)

⚠️ Yesterday is the most recent date with data. Today's data isn't available yet.

Response example:

{
  "response": {
    "appid": 1234567,
    "date": "2026-04-03",
    "wishlist_summary": {
      "wishlist_adds": 15,
      "wishlist_deletes": 3,
      "wishlist_purchases": 2,
      "wishlist_gifts": 0,
      "wishlist_adds_windows": 12,
      "wishlist_adds_mac": 2,
      "wishlist_adds_linux": 1
    },
    "country_summary": [
      {
        "country_code": "US",
        "country_name": "United States",
        "region": "North America",
        "summary_actions": { "wishlist_adds": 5 }
      }
    ],
    "language_summary": [
      {
        "language": 0,
        "language_name": "english",
        "summary_actions": { "wishlist_adds": 8 }
      }
    ],
    "app_min_date": "2025-01-15"
  }
}

app_min_date tells you the earliest date data exists for this app. Don't request dates before this. You'll just get empty responses.

GetChangedDatesForPartner

GET https://partner.steam-api.com/IPartnerFinancialsService/GetChangedDatesForPartner/v001/
    ?key={key}
    &highwatermark=0

Returns dates that have new or updated financial data. Use this for efficient syncing. Only re-fetch dates that appear in this list instead of polling every day.

{
  "response": {
    "dates": ["2026/04/01", "2026/04/02", "2026/04/03"]
  }
}

⚠️ Date format gotcha: These dates use slashes (YYYY/MM/DD), but all other endpoints use dashes (YYYY-MM-DD). You'll need to convert: date.replace(/\//g, '-').


Endpoints: Publisher Key Only

These require a Publisher key associated with the app. They use partner.steam-api.com.

GetGlobalStatsForGame

GET https://partner.steam-api.com/ISteamUserStats/GetGlobalStatsForGame/v1/
    ?key={key}
    &appid={appid}
    &count=1
    &name[0]=stat_name

Returns aggregated global stats with optional date range filtering.

Parameter Description
name[0], name[1], etc. Stat names to retrieve
count Number of stats requested
startdate, enddate Optional Unix timestamps for daily aggregates

Prerequisite: Your app must have stats defined in Steamworks → App Admin → Stats & Achievements. You need to know stat names. Use GetSchemaForGame to discover them.

GetPartnerAppListForWebAPIKey

GET https://partner.steam-api.com/ISteamApps/GetPartnerAppListForWebAPIKey/v2/?key={key}

Returns all apps your publisher key has access to. Very useful for verifying your key is set up correctly.

GetPlayersBanned

GET https://partner.steam-api.com/ISteamApps/GetPlayersBanned/v1/?key={key}&appid={appid}

Returns a list of banned players for your game.

GetLeaderboardsForGame

GET https://partner.steam-api.com/ISteamLeaderboards/GetLeaderboardsForGame/v2/?key={key}&appid={appid}

Returns all leaderboards defined for your game.

Prerequisite: Leaderboards must be created in Steamworks → App Admin → Leaderboards first.

ISteamMicroTxn/GetReport

GET https://partner.steam-api.com/ISteamMicroTxn/GetReport/v5/
    ?key={key}
    &appid={appid}
    &type=GAMESALES
    &time={RFC3339}
    &maxresults=1000

Returns microtransaction reports. Report types: GAMESALES, STEAMSTORESALES, SETTLEMENT, CHARGEBACK, SUBSCRIPTION.

Prerequisite: Your app must use Steam microtransactions.


Regional Pricing Lookup

To check your game's price in different regions, call the Store API with a country code:

# US (default)
curl "https://store.steampowered.com/api/appdetails?appids={appid}&cc=us"

# Eurozone
curl "https://store.steampowered.com/api/appdetails?appids={appid}&cc=de"

# Türkiye
curl "https://store.steampowered.com/api/appdetails?appids={appid}&cc=tr"

# China
curl "https://store.steampowered.com/api/appdetails?appids={appid}&cc=cn"

# Brazil
curl "https://store.steampowered.com/api/appdetails?appids={appid}&cc=br"

# Japan
curl "https://store.steampowered.com/api/appdetails?appids={appid}&cc=jp"

The price_overview object in the response contains:

  • currency: e.g., "USD", "EUR", "TRY", "CNY"
  • initial: base price in cents
  • final: current price after discount, in cents
  • discount_percent: active discount percentage

Steam Language Codes

Steam uses its own language codes for API calls and store pages. Some of these are non-standard (like schinese, tchinese, brazilian, koreana, latam), so you can't just use ISO codes.

English Name Native Name API Language Code Web API Code
Arabic العربية arabic ar
Bulgarian български език bulgarian bg
Chinese (Simplified) 简体中文 schinese zh-CN
Chinese (Traditional) 繁體中文 tchinese zh-TW
Czech čeština czech cs
Danish Dansk danish da
Dutch Nederlands dutch nl
English English english en
Finnish Suomi finnish fi
French Français french fr
German Deutsch german de
Greek Ελληνικά greek el
Hungarian Magyar hungarian hu
Indonesian Bahasa Indonesia indonesian id
Italian Italiano italian it
Japanese 日本語 japanese ja
Korean 한국어 koreana ko
Norwegian Norsk norwegian no
Polish Polski polish pl
Portuguese Português portuguese pt
Portuguese (Brazil) Português-Brasil brazilian pt-BR
Romanian Română romanian ro
Russian Русский russian ru
Spanish (Spain) Español-España spanish es
Spanish (Latin America) Español-Latinoamérica latam es-419
Swedish Svenska swedish sv
Thai ไทย thai th
Turkish Türkçe turkish tr
Ukrainian Українська ukrainian uk
Vietnamese Tiếng Việt vietnamese vi

Source: Steamworks Languages Documentation

Note: API language codes are used with Steamworks client-side APIs. Web API language codes are used with the Steamworks Web API. Additional languages (Afrikaans, Albanian, Hebrew, Hindi, etc.) are available for store page language selection only and are not supported in APIs.

💡 Pro tip: You can preview any Steam store page in a different language by adding ?l= to the URL. For example: store.steampowered.com/app/3349960/okeygg/?l=turkish shows the okey.gg store page in Turkish. Use the API language codes from the table above (not the Web API codes).


Packages and Bundles

Steam doesn't sell apps directly. Every purchase goes through a package (also called a "sub"). Even if your game has no DLC, no editions, and no bundles, it still has at least one default package that was created automatically.

Why this matters: Some Steamworks features (like refund data) use Package ID instead of App ID. If you're looking for your refund stats and your App ID doesn't work in the URL, you probably need the Package ID instead.

How to find your Package ID:

  1. Go to partner.steamgames.com/apps/associated/{appid}
  2. Look under "All Associated Packages"
  3. Your default package is usually named "{Game Name} for Steam" or similar

For example, okey.gg has App ID 3349960 and its default package ID is 1185712.

Bundles are different from packages. A bundle groups multiple packages together at a discount (like a "Complete Edition" that includes the base game + all DLC). Bundles have their own Bundle ID and are managed in Steamworks → Store Page → Bundles. Bundle pricing is calculated from the combined package prices minus the bundle discount.

Learn more: Steamworks Packages Documentation


Data NOT Available via API

Some data only exists in the Steamworks Partner Portal web interface. There are no API endpoints for these. Valve simply doesn't expose them.

Data Where to find it
Store page traffic partner.steamgames.com/apps/navtrafficstats/{appid}
UTM campaign analytics partner.steamgames.com/apps/utmtrafficstats/{appid}
Refund details & reasons partner.steampowered.com/package/refunds/{packageid}/

These portal pages do offer CSV export if you need the data elsewhere.

⚠️ Refunds use Package ID, not App ID. Steam organizes purchases by packages (also called "subs"), not by App ID. Every game has at least one package. To find your package ID, go to partner.steamgames.com/apps/associated/{appid} and look under "All Associated Packages". For example, okey.gg has App ID 3349960 but its main package ID is 1185712.

Learn more about packages: Steamworks Packages Documentation


Common Gotchas

Things that will trip you up if nobody warns you. Consider yourself warned.

Date formats are inconsistent

Endpoint Date format Timezone
GetDetailedSales YYYY-MM-DD (dashes) Pacific Time
GetAppWishlistReporting YYYY-MM-DD (dashes) GMT
GetChangedDatesForPartner YYYY/MM/DD (slashes) -

Yes, sales data uses Pacific Time and wishlist data uses GMT. And changed dates use slashes while everything else uses dashes. Welcome to Steam.

Financial values are strings, not numbers

Fields like gross_sales_usd, net_sales_usd, base_price come back as "9.9900" (a string), not 9.99 (a number). Always convert:

// ❌ Wrong: this compares strings
if (item.gross_sales_usd > 0) { ... }

// ✅ Correct
if (parseFloat(item.gross_sales_usd) > 0) { ... }

Empty response ≠ error

When your publisher key is valid but missing the "Sales Data" permission, Steam returns:

{ "response": {} }

No error code. No error message. Just... nothing. If you're getting empty responses from IPartnerFinancialsService, check your key's permissions in Steamworks.

Serverless + IP whitelisting don't mix

If you deploy to Vercel, AWS Lambda, Cloudflare Workers, or any serverless platform, your server's IP address changes with every request. If your Steam key has IP whitelisting enabled, every request will fail.

Fix: Remove IP restrictions from your key in Steamworks, or use a fixed-IP proxy.

Not all dates have sales data

Some days your game just doesn't sell. The API returns empty results for those dates. That's normal, not an error. Use GetChangedDatesForPartner to find which dates actually have data instead of blindly requesting every date.

Wishlist data has a minimum date

Each app has an app_min_date (returned in the wishlist response). Data before that date doesn't exist. Don't waste requests on dates before it.


Error Reference

What you see What it means How to fix
HTTP 403 + "Access is denied" HTML page Wrong key type for this host Use a publisher/financial key for partner.steam-api.com. A regular Web API key won't work.
HTTP 200 + {"response":{}} Key is valid but missing permission Enable "Sales Data" permission on the publisher group in Steamworks
HTTP 200 + {"response":{"result":8}} No stats/data configured Set up stats, achievements, or leaderboards in Steamworks first
HTTP 429 Rate limited Slow down. Add caching.
Connection timeout on partner API IP blocked by whitelist Remove IP restrictions from key, or add your server IP

Steamworks Setup Checklist

Some endpoints return nothing until you configure the corresponding feature in Steamworks. Here's what to set up and what it unlocks:

Feature Where to configure What it unlocks
Stats Steamworks → App Admin → Stats & Achievements → Stats GetGlobalStatsForGame: aggregated game stats with time ranges
Achievements Steamworks → App Admin → Stats & Achievements → Achievements GetGlobalAchievementPercentagesForApp: unlock percentages
Leaderboards Steamworks → App Admin → Leaderboards GetLeaderboardsForGame + GetLeaderboardEntries
Microtransactions Steamworks → App Admin → Microtransaction Configuration ISteamMicroTxn/GetReport: transaction reports
Steam Inventory Steamworks → App Admin → Steam Inventory Service IInventoryService endpoints

Official References


AI Agent Skill

This guide is also available as an AI agent skill. If you use Claude Code or similar AI coding tools, you can install the steamworks-api-specialist skill to give your AI assistant deep knowledge of the Steam Web API — key types, endpoint details, common gotchas, and troubleshooting flows — so it can help you integrate faster.


Contributing

Found an error? Know about an endpoint we missed? Want to add a translation?

We'd love your help. Check out our Contributing Guide for details.

Quick version:

  1. Fork this repo
  2. Make your changes
  3. Submit a PR

Translations go in translations/README.{language-code}.md. See existing translations for reference.

If this guide saved you time, consider giving it a ⭐. It helps other indie devs find it too.


License

CC0 1.0 Universal (Public Domain). Do whatever you want with this. Copy it, modify it, include it in your project, sell a course around it. No attribution required (but it's always appreciated 🙏).



Made with ❤️ by yilmaz.games

We built this guide while integrating Steam APIs for our game okey.gg.
If it helped you out, a wishlist means the world to a small studio 🙏

Last updated: April 2026

About

A practical guide to the Steamworks Web API covering sales data, wishlist reporting, reviews, player counts, achievements and partner endpoints. Focused on real-world usage, common pitfalls and clear examples for game developers.

Resources

Contributing

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors