Games & Comics — entry 041 of 75

Magic The Gathering

Verified Aug 2026

magicthegathering.io is a keyless, community-run REST API covering Magic: The Gathering cards, sets, types, and formats, backed by a full JSON dump of card data. It predates Wizards' own Gatherer API push and is now the slower, less actively maintained option compared to Scryfall, though it remains live and free with no registration required.

magicthegathering.io is a keyless, community-run REST API for Magic: The Gathering cards, sets, and types. A live GET this run against /cards?name=Black%20Lotus&pageSize=1 returned a genuine 1,023 B one-card response at HTTP 200, content-type: application/json; charset=utf-8 — with pagination and rate-limit data carried entirely in the response headers, not the body.

trading-card-gamecard-datakeylesscommunity-run
AuthenticationNone requiredCall it straight away — no key, no signup.
HTTPSSupportedTraffic is encrypted in transit.
CORSEnabledCallable directly from browser JavaScript.
PricingFreeNo paid tier — free for the documented use case.
FormatsJSONResponses can be requested as JSON.

GreatAPIs Score

Score88out of 100
Authentication25/25No authentication required
Pricing20/20Free to use
Docs14/20Documentation URL provided
Formats9/15Single response format
Freshness20/20Verified within 6 months

Embed this badge

Scored 88 on greatapis.com
<a href="https://greatapis.com/api/magic-the-gathering/"><img src="https://greatapis.com/badge/magic-the-gathering.svg" alt="Scored 88 on greatapis.com"></a>

Auth quickstart

  1. No API key, signup, or credit card required — the live GET above returned real card data with no auth header of any kind attached. With an Origin header this run, the response added access-control-allow-origin: * plus access-control-expose-headers: Link, Page-Size, Count, Total-Count, Ratelimit-Limit, Ratelimit-Remaining — that expose-headers list matters: without it, a browser fetch() can read the response body but not the paging/rate-limit headers described below.
Stored keyNo key stored

Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.

Search cards by name

GEThttps://api.magicthegathering.io/v1/cards?name=Black%20Lotus&pageSize=1

200 application/json; charset=utf-8

{
  "cards": [
    {
      "name": "Black Lotus",
      "manaCost": "{0}",
      "cmc": 0.0,
      "type": "Artifact",
      "types": ["Artifact"],
      "rarity": "Rare",
      "set": "2ED",
      "setName": "Unlimited Edition",
      "text": "{T}, Sacrifice Black Lotus: Add three mana of any one color.",
      "artist": "Christopher Rush",
      "number": "233",
      "printings": ["2ED", "30A", "CED", "CEI", "LEA", "LEB", "O90P", "OVNT", "PRM", "VMA", "YDMU"],
      "legalities": [
        { "format": "Legacy", "legality": "Banned" },
        { "format": "Vintage", "legality": "Restricted" }
      ],
      "id": "e6c9fe58-bc4f-529d-a387-77d61af87de4"
    }
  ]
}

The same live response's headers this run carried count: 1, total-count: 13 (13 total printings match name=Black Lotus across all sets), link: <https://api.magicthegathering.io/v1/cards?name=Black+Lotus&page=13&pageSize=1>; rel="last", <https://api.magicthegathering.io/v1/cards?name=Black+Lotus&page=2&pageSize=1>; rel="next", and ratelimit-limit: 1000 / ratelimit-remaining: 998 — none of that paging or quota information appears anywhere in the JSON body above.

Try it

Developer reference

Base URLhttps://api.magicthegathering.io/v1
Rate limit

1,000 requests/hour per IP (live Ratelimit-Limit/Ratelimit-Remaining headers on api.magicthegathering.io) -- docs.magicthegathering.io separately states third-party apps are throttled to 5,000 requests/hour, higher than the ceiling actually observed live.

Key endpoints
  • GET/cards
  • GET/cards/{id}
  • GET/sets
  • GET/types

Gotchas & limits

  • Pagination and rate limits live entirely in HTTP headers, not the body — confirmed live above: the JSON body is just {"cards": [...]}, while count, total-count, link (with rel="next"/rel="last"), ratelimit-limit, and ratelimit-remaining are all headers. A client that only parses the response body can't page through results or see its own remaining quota.
  • The link header re-spells the query with + for spaces, not %20 — confirmed live above: a request with name=Black%20Lotus gets back a link header reading name=Black+Lotus. Copy the header's URL verbatim rather than assuming it echoes your original encoding.
  • cmc (converted mana cost) is a JSON float, not an int — confirmed live above: Black Lotus's cmc is 0.0. Code that does strict integer type-checking on cmc will reject a perfectly valid card.
  • /types mixes case-duplicated and unrelated junk into one flat array — a live GET this run against /types (290 B) returned {"types":["Artifact","Battle","Conspiracy","Creature","Dragon","Elemental","Enchantment","Goblin","Hero","instant","Instant","Jaguar","Kindred","Knights","Land","Legend","Phenomenon","Plane","Planeswalker","Scheme","Sorcery","Stickers","Summon","Tribal","Universewalker","Vanguard","Wolf"]} — an object envelope around the array, like every other endpoint here, not a bare array. Inside it, note both lowercase "instant" and proper-case "Instant" present simultaneously, plus creature subtypes (Dragon, Goblin, Jaguar, Hero) that aren't card types at all. Treat this list as unreliable for validating a card's type field.
  • A no-match lookup is a real 404 with a compact JSON body — a live GET this run against /cards/nonexistent-id-xyz returned HTTP 404 with the 34 B body {"status":404,"error":"Not Found"}, distinct from the {"cards":[...]} success shape above.

Availability

Uptime100%
Median latency311 ms
Last checkUp · 200 · Sep 2026

3 checks since Aug 2026. A person runs this check by hand, not an automated monitor.