Games & Comics — entry 041 of 75
Magic The Gathering
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.
GreatAPIs Score
Auth quickstart
- 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
Originheader this run, the response addedaccess-control-allow-origin: *plusaccess-control-expose-headers: Link, Page-Size, Count, Total-Count, Ratelimit-Limit, Ratelimit-Remaining— that expose-headers list matters: without it, a browserfetch()can read the response body but not the paging/rate-limit headers described below.
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
{
"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
https://api.magicthegathering.io/v11,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.
- 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": [...]}, whilecount,total-count,link(withrel="next"/rel="last"),ratelimit-limit, andratelimit-remainingare all headers. A client that only parses the response body can't page through results or see its own remaining quota. - The
linkheader re-spells the query with+for spaces, not%20— confirmed live above: a request withname=Black%20Lotusgets back alinkheader readingname=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'scmcis0.0. Code that does strict integer type-checking oncmcwill reject a perfectly valid card./typesmixes 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'stypefield.- A no-match lookup is a real 404 with a compact JSON body — a live GET this run against
/cards/nonexistent-id-xyzreturned HTTP 404 with the 34 B body{"status":404,"error":"Not Found"}, distinct from the{"cards":[...]}success shape above.