Being Human — Internal Docs
Integrations

Steam

Steamworks integration — what exists, what's stubbed, the launch checklist

The game ships on Steam (native) with a browser build alongside — so Steam is treated as one distribution channel, never the source of truth. Everything Steam-specific is isolated in apps/api/src/steam.ts.

What works today

createSteamClient(env) returns a client that mirrors achievement unlocks via ISteamUserStats/SetUserStatsForGame. Without credentials it's a logged no-op, so calling code never branches:

[steam] disabled — would unlock FIRST_STEPS for 7656119… (set STEAM_WEB_API_KEY + STEAM_APP_ID)

Reality check: there are no Steam webhooks

Steam does not push events for game happenings. The only callback-style API is for microtransactions (ISteamMicroTxn), and even that is request/response. So the integration direction is:

  • We push to Steam: achievement unlocks (done), stats (same endpoint, when needed).
  • We poll from Steam: wishlist totals, review counts, player counts — a scheduled job hitting the partner Web API, feeding #dev-log. Not built yet; small and additive when wanted.

Launch checklist

  1. Steamworks account + app id — partner.steamgames.com; put the app id in STEAM_APP_ID.
  2. Publisher Web API key — Steamworks → Users & PermissionsManage Groups → your group → Create WebAPI Key. This is a publisher key (server-to-server, works with partner.steam-api.com), not a personal key from steamcommunity.com/dev. Store as STEAM_WEB_API_KEY — server env only, never the client.
  3. Define achievements — Steamworks → Stats & Achievements: for each entry in packages/shared/src/achievements.ts, create an achievement whose API Name equals the key (FIRST_STEPS, …). Names/descriptions/icons live in Steamworks per locale; our name/description are the canonical English strings.
  4. Sign in with Steam — better-auth generic provider against Steam OpenID 2.0, storing steamId64 as account.accountId with providerId: "steam". Mirroring already keys off exactly this — no other code changes.
  5. In-game unlocks — the Rust client also calls the Steamworks SDK locally for the instant overlay popup; the API call is what makes it canonical and cross-platform.

Multiplayer, eventually

Steam networking/lobbies are a client-side SDK concern in the Rust repo. This backend's role stays identity + meta-services (architecture notes).

On this page