Every free-to-keep PC game, confirmed against the store’s own API before it ships. One call instead of six, one shape instead of four — and a negative you can trust: when we say nothing is free on Steam right now, it’s because we asked Steam this hour.
Confirmed against the store's own API before publication. Not aggregated, not inferred from a listicle.
Per-store status, so an agent can say "nothing is free there" as fact instead of guessing.
Pay per pull. Between pulls, conditional checks are free for 24 hours — poll as often as you like.
No signup, no API-key application, no human in the loop. The payment receipt is the credential — an agent can discover, pay and consume this entirely on its own.
4xx and 5xx are always free, and a lost response never double-charges: re-present the same payment proof and get your access back.
This is an N2N service: designed for autonomous agents, MCP servers and machine-to-machine pipelines rather than people clicking buttons. Discovery is machine-readable (llms.txt, OpenAPI 3.1), payment is HTTP 402 with no onboarding, and the response carries provenance — which store confirmed each entry and when — so a model can cite it instead of guessing.
While building this, a widely used free-games aggregator listed a title as an active Steam giveaway — with an end date. Steam’s own API reported the same game at $3.99, with no free-to-keep flag set.
Anything built on scraped aggregation publishes that game as free. Here it was discarded, because the store itself disagreed. That is the entire product: “nothing is free on Steam right now” is a fact a language model cannot safely generate on its own — and cannot verify without making the calls itself.
You are billed when the data changes, never when you ask. Checking costs nothing, so an agent polling every minute and one polling once a day pay exactly the same. Your bill is a function of how often games actually become free — a handful of times a day — not of how carefully your loop is written.
That makes autonomous spend predictable enough to approve in advance, which is usually the real blocker for agent purchasing rather than the price.
# 1. Ask. You'll get a 402 with a payment challenge. curl -i https://soren.com/v1/free-games # 2. Pay, and present the proof. You get the feed and a 24h token. curl -i https://soren.com/v1/free-games \ -H "X-Payment: <proof>" # 3. For the next 24h, check for changes for free. # 304 = nothing new. 402 = something changed, pay to pull it. curl -i https://soren.com/v1/free-games \ -H "Authorization: Bearer <token>" \ -H 'If-None-Match: "<version>"'
{
"version": "733d91c2…", // changes only when content does
"updated_at": "2026-07-31T15:17:52Z",
"free_games": [
{ "title": "OTXO", "store": "epic", "igdb_id": null,
"claim_url": "https://store.epicgames.com/en-US/p/otxo-396b8b",
"starts_at": "2026-07-30T15:00:00Z",
"ends_at": "2026-08-06T15:00:00Z" }
],
"stores": {
"steam": { "status": "ok", "free_count": 0,
"note": "verified against steam: no free-to-keep games at this time" },
"gog": { "status": "unavailable", "free_count": null,
"note": "could not be reached — NOT a statement that nothing is free" }
}
}
ok with
0 means we asked and there is nothing. unavailable
means we could not check. Rendering the second as "nothing is free" is the
exact false negative this feed exists to prevent.
| Endpoint | What | Price |
|---|---|---|
GET /v1/free-games | Currently claimable, all stores | $0.02 / pull |
GET /v1/upcoming | Announced but not started yet | $0.01 / pull |
POST /mcp | MCP server — same data, same billing | see below |
GET /v1/status | Service health | free |
GET /openapi.json | OpenAPI 3.1 spec | free |
GET /llms.txt | What this is, for agents | free |
Each game carries the exact endpoint and test that confirmed it, plus when we first saw it — so an answer can be specific rather than a general appeal to having checked.
{
"title": "OTXO",
"claim_url": "https://store.epicgames.com/en-US/p/otxo-396b8b",
"source": "epic:freeGamesPromotions (discountPercentage === 0, active window)",
"first_seen": "2026-07-31T00:20:01.987Z"
}
There is deliberately no per-game verified_at: every
entry from a store is confirmed in the same pass, so it would duplicate the
store-level timestamp — and being a per-run value inside the hashed
content, it would change the version every pass and bill every check.
Freshness lives at the store level; origin lives on the entry.
Every response carries a version that is a SHA-256 of
its own content. Recompute it and a match proves the payload
reached you exactly as published — unaltered by us, by a cache, or by
anything in between.
// dependency-free, works in Node, Deno, Bun and browsers import { verifyFeed } from 'https://soren.com/verify.js'; const feed = await (await fetch('https://soren.com/v1/free-games', { headers })).json(); console.log(await verifyFeed(feed)); // { valid: true, ... }
Timestamps are excluded from the hash, so a refresh that changes nothing leaves the version untouched. That is the same property your billing rests on: an unchanged version is genuinely unchanged data.
Point your agent at https://soren.com/mcp — streamable
HTTP, JSON-RPC 2.0, no separate signup. Four tools:
get_free_games and get_upcoming (paid),
check_for_changes and get_status (free).
Calling a paid tool without a payment proof returns payment instructions, not an error — so an agent can discover the price and pay without a human ever being involved.
| Code | Meaning | Billed |
|---|---|---|
200 | Feed returned, fresh 24h token issued | yes |
304 | Nothing changed since your version | no |
402 | Payment needed, or the feed changed | no |
429 | Rate limited — wait Retry-After seconds | no |
503 | Feed stale or unpublished — we fail rather than serve it | no |
Every payload carries an Ed25519 signature over its version
string, with the public key at
/signing-key.json. The signature proves it
came from us; recomputing the hash proves the content is what was signed.
verifyFully() does both.
And the shape holds still. Within /v1: fields are
never removed or retyped, meanings never silently change,
and the canonical hash form is fixed. Additions can appear without notice
— ignore unknown fields. Breaking changes ship at /v2
with 180 days’ notice.
Full contract.
/v1/status is free and unauthenticated, and reports how often we were right — not how much is free. Runs attempted and how many were clean, per-store reachability, offers published, and offers that vanished before the store’s own stated deadline.
It is generated from the database, not written by hand, so a bad week cannot be quietly left out. A source that publishes its own anomalies is easier to believe than one reporting a spotless record.
Steam · Epic · GOG · itch.io — checked hourly. Free-to-keep only: no demos, no free-to-play, no free weekends, no raffles, no key drops you have to earn.