MTG Finance Signals API

FreeNo keyOpen CORSCached

Use Scryfall for card objects and oracle text. Use SpellBook Finance for the derived market signals it does not compute: price movers, all-time-high breaks, set value trends, RSS feeds, and sealed EV rankings. All public JSON and RSS, no API key, no sign-up, open CORS.

Listed in awesome-mtg Developer Resources

Quick start: today's all-time-high breaks

const res = await fetch("https://api.spellbook-finance.com/ath");
const { data } = await res.json();
console.log(data.surpassedAth.slice(0, 5));

What this is, and what it is not

SpellBook Finance is not a card catalog replacement. It exposes derived finance data built from market history, sealed EV calculations, and set-level price snapshots. Endpoints send long Cache-Control headers and refresh on daily and hourly schedules, not per second.

Extractable facts
Short source, access, and refresh notes for bots, dashboards, and docs that need to describe the API accurately.
  • SpellBook Finance is listed in awesome-mtg Developer Resources as a free, keyless MTG market data API.
  • Use Scryfall for card objects and oracle text. Use SpellBook Finance for derived finance signals Scryfall does not compute.
  • Price movers, all-time-high breaks, buyout detection, and sealed EV rankings are derived from SpellBook market-history snapshots.
  • Public JSON endpoints and RSS feeds require no account, no API key, and support browser JavaScript through open CORS.
  • Public feed and embed endpoints carry a 120 requests per minute per-IP rate limit and return Retry-After on 429 responses.
  • Machine-readable endpoint manifest: /api-signals.json.
Market data
The signals that move the MTG secondary market, recomputed daily and hourly.
GET/movers?timeframe=daily

Biggest price gainers and losers, computed from SpellBook price-history snapshots. timeframe = daily or weekly.

Returns { data: { gainers: [], losers: [] } }

GET/ath

Cards that just passed, or are near, their all-time-high price. ATH detection runs on SpellBook's full historical series (not Scryfall's current price).

Returns { data: { surpassedAth: [], nearAth: [] } }

GET/ticker

A compact market ticker of the day's notable movers.

Returns { data: [{ name, price, changePct, direction }] }

GET/buyouts

Cards detected spiking or getting bought out in the last 7 days, scored from SpellBook market price history.

Returns { buyouts: [{ name, setCode, oldPrice, newPrice, pctGain, detectedAt }] }

Sealed and box EV
Per-printing expected value for sealed product, the same numbers behind the EV rankings.
GET/embed/ev/rankings?count=10

Top booster boxes ranked by EV ratio. count = 1 to 25.

Returns { data: { rankings: [{ boxId, boxName, totalEV, evRatio, marketPrice }] } }

GET/embed/ev/{boxId}

EV for a single box by tcgProductId (get an id from the rankings above), with notable cards and eBay sold-comp fields when covered.

Returns { data: { boxId, boxName, totalEV, evRatio, marketPrice, spreadUsd, notableCards: [{ ebayMedianUsd, ebaySaleCount }] } }

GET/embed/sold-comps/{cardId}

Recent eBay sold median and resale anchor for one Scryfall card id or SpellBook card slug. Missing coverage returns a labeled empty payload.

Returns { data: { cardId, oracleId, dataState, ebayMedianUsd, ebaySaleCount, resaleAnchorUsd, resaleAnchorSource } }

Sets
Catalog data for every MTG set.
GET/sets

Every MTG set with codes and release info.

Returns { data: [...] }

GET/sets/{setCode}

One set plus its card list.

Returns { data: {...} }

Subscribe feeds (RSS)
Standards-compliant RSS for feed readers and Discord RSS bots. No polling code required.
GET/feeds/movers.xml

Daily gainers and losers as an RSS feed.

Returns application/rss+xml

GET/feeds/buyouts.xml

Buyout and spike detections as an RSS feed.

Returns application/rss+xml

Use it in a spreadsheet
Track your collection in Google Sheets? Paste this once under Extensions, Apps Script, and you get a live price function. No add-on to install, no key.
/**
 * SpellBook Finance live MTG price.
 * Usage:  =SPELLBOOK("Ragavan, Nimble Pilferer")
 *         =SPELLBOOK("Lightning Bolt", "MH2")   // pin a set
 */
function SPELLBOOK(name, setCode) {
  if (!name) return "";
  var url = "https://api.spellbook-finance.com/cards/find?q=" +
    encodeURIComponent(name);
  var res = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
  var rows = (JSON.parse(res.getContentText()).data) || [];
  if (setCode) {
    rows = rows.filter(function (c) {
      return (c.setCode || "").toLowerCase() === String(setCode).toLowerCase();
    });
  }
  return rows.length ? Number(rows[0].priceUsd) : "";
}

Then use it like any formula: =SPELLBOOK("Ragavan, Nimble Pilferer") or pin a printing with =SPELLBOOK("Lightning Bolt", "MH2"). It returns the current market price in USD. Sheets caches custom functions, so it stays light on recalcs.

Using the API
  • Every endpoint is GET, returns JSON (or RSS for feeds), and needs no key.
  • CORS is open, so you can call these directly from browser JavaScript.
  • Responses send long Cache-Control headers, so cache on your side and avoid hammering; the data refreshes on daily and hourly schedules, not per second.
  • Endpoint metadata is also published at /api-signals.json.
  • The public feed and embed endpoints carry a generous per-IP rate limit (120 requests/minute). A 429 with a Retry-After header means slow down and try again shortly.
  • A link back to spellbook-finance.com is appreciated when you publish something built on this data.
  • Want ready-made surfaces instead of raw data? See SpellBook Live for the stream overlay and embeddable widgets.