fkrzski/laravel-steam-api-sdk
Laravel SDK for the Steam Web API, giving you a clean, configurable PHP interface to fetch player profiles, owned games, achievements, stats, and news with expressive fluent methods and sensible defaults.
^0.9):
composer require fkrzski/laravel-steam-api-sdk
php artisan vendor:publish --tag=steam-api-config
.env:
STEAM_API_KEY=...
use Fkrzski\LaravelSteamApiSdk\Facades\Steam;
$me = Steam::users()->summaries(SteamId::make('7656119...'));
php artisan about — confirm the key is picked up and read the new "Requests Remaining", "429 Cool-down" and "Sender" rows.Steam::webApi()->serverTime() — zero-risk smoke test of connectivity: it returns Steam's clock as a DateTimeImmutable (UTC) and never sends your key.Steam::webApi()->supportedApis() — lists the Web API methods your key can call (falls back to the unauthenticated list if no key is configured). Great for verifying key permissions and for discovering which resource a given endpoint lives on.Where to look first: the API reference (which resource holds which endpoint — this changed in 0.9.0), the new rate limiting docs page, and the base SDK's hooks page linked from the docs.
Always go through resources. The 19 facade helpers (Steam::summaries() … Steam::appNews()) are gone. Each call keeps its name, arguments and return type, so migration is mostly adding the resource segment:
Steam::groups($id); // → Steam::users()->groups($id)
Steam::currentPlayers(440); // → Steam::stats()->currentPlayers(440)
Steam::newsFeed(); // unchanged, still on the facade
A quick grep for Steam:: in your app plus the API reference will surface every site to update.
Own limits instead of the fixed daily cap. Configure in config/steam-api.php:
'rate_limit' => [
'limits' => [
['allow' => 100, 'every' => 60, 'sleep' => 1000], // per-minute guard
['allow' => 100000, 'every' => 'day'], // Steam's daily budget, resets 00:00 UTC
],
'cooldown' => 60, // seconds held back after a 429 without Retry-After
],
limits => [] disables local metering entirely (useful in tests, or when you meter elsewhere). Note the day boundary is UTC midnight, not 24h after the first request — align any of your own windowing logic with that.
Queue jobs that touch Steam. Wrap jobs with RespectsSteamRateLimit; it releases the job until the next UTC midnight when the daily budget is spent, rather than failing it. Pair this with a limit set in config so the trait knows what's left.
Custom HTTP sender via the container. Middleware now lives on a GuzzleSender subclass that the container builds:
// AppServiceProvider::register()
$this->app->bind(\Fkrzski\PhpSteamApiSdk\Http\Senders\GuzzleSender::class, function () {
$sender = new class extends \Fkrzski\PhpSteamApiSdk\Http\Senders\GuzzleSender {
// add your middleware / handler stack here
};
return $sender;
});
STEAM_API_SENDER=App\Steam\MyGuzzleSender
Use this for retry/logging/tracing middleware, a proxy, or to point the Guzzle client at a stubbed handler in local environments. Because the sender is resolved each time the connector is built, a request-scoped binding will take effect (e.g. swapping in a mock per test).
Test with the fluent fake, which now covers the new endpoints:
Steam::fake([
'*GetPlayerSummaries*' => Steam::response()->users()->summaries(...),
]);
Steam::fake()->webApi()->serverInfo(); // clock
Steam::fake()->webApi()->supportedApiList(); // authenticated method list
Steam::fake()->webApi()->supportedApiListInvalidKey();
Steam::fake()->users()->summaries()->friendsOnly(); // profile read back as CommunityVisibility::FriendsOnly
Use the factory helpers (PlayerSummaryFactory::friendsOnly(), WebApiMethodFactory, WebApiParameterFactory) to build realistic batches, including the friends-only case that used to blow up whole 100-profile calls.
Observability. With laravel/nightwatch installed and enabled, Steam calls appear as outgoing requests with the API key stripped from recorded URLs — useful for spotting slow endpoints or 429 storms in staging. Combine with the about "Requests Remaining" row to decide whether a job should even be dispatched.
Health/ops surface. A tiny scheduled command calling Steam::webApi()->serverTime() is a cheap liveness probe (no key spent, no quota spent) — good for an uptime check that actually exercises your credentials path minus the key.
Steam::connector()->sender() now returns the SDK's SteamSender wrapper, so addMiddleware(), getHandlerStack() and getGuzzleClient() are gone — move that code into a GuzzleSender subclass as above.InvalidSteamRateLimitStoreException → InvalidSteamRateLimitOptionException. Catching the old name silently won't catch. It now guards the whole steam-api.rate_limit block, so a typo in limits/cooldown throws from here — check the message, it usually points at the offending key.http.sender, rate_limit.limits or rate_limit.cooldown — your values are used, but STEAM_API_SENDER and STEAM_API_RATE_LIMIT_COOLDOWN are unread until you copy those keys into the published file. If the sender binding "doesn't work", this is almost always why.100000_every_utc_midnight, so any persistent rate-limit store restarts from zero once on upgrade. Harmless, but don't be alarmed by a burst on deploy.about --json consumers. daily_requests_remaining → requests_remaining, and it's now a list spanning every configured limit rather than a single number. Update dashboards and any assertions in CI.cooldown is non-zero, and remember it only applies to 429s without Retry-After.serverTime() never sends it; supportedApis() sends it only when configured. Prefer these for unauthenticated smoke tests so keys stay out of logs and third parties.Sender (config/container), rate limit store (persistent store config for multi-node fleets), and the factories for building realistic fakes. Pre-1.0, so pin the package and the base SDK in lockstep (^0.9) and read the Upgrading section before every minor bump.How can I help you explore Laravel packages today?