Magic: The Gathering Developers

Getting Started

Welcome to the Magic: The Gathering API! You can use the API to access Magic: The Gathering API endpoints, which can get information on cards and sets. All API access is performed over HTTPS and accessed from the https://api.magicthegathering.io domain.

To use the API endpoints, the format is as follows:

https://api.magicthegathering.io/<version>/<resource>

For example:

https://api.magicthegathering.io/v1/cards

There are multiple SDKs available to make it even easier to consume the API. To chat with other developers and discuss the API and SDKs, check out the Discord Server!

mtg-developers on discord

Developer SDKs

There are multiple developer SDKs available. To see how to install and use them, refer to the links below:

Rate Limits

Overview

Rate limits are enforced for all third-party applications and services. This document is an overview of the rate limits themselves, as well as how they are enforced and best practices for handling the errors returned when a rate limit is reached.

Third-party applications are currently throttled to 5000 requests per hour. As this API continues to age, the rate limits may be updated to provide better performance to users

Rationale

As previously mentioned, the primary goal is to provide a responsive interface for developers and users to use when accessing the MTG data. Since each request made to the API incurs a computational cost, it’s in the best interest of both Magic: The Gathering API and its developer partners that these costs be minimized to the greatest degree possible.

Rate limiting also helps third-party developers by encouraging them to build their integrations to make economical use of API requests.

HTTP/1.1 403 Forbidden
Date: Mon, 21 Apr 2014 13:26:48 GMT
Content-Type: application/json; charset=utf-8
{
  "message": "Rate Limit Exceeded"
}

Errors

Code Name Description
400 Bad Request We could not process that action
403 Forbidden You exceeded the rate limit
404 Not Found The requested resource could not be found
500 Internal Server Error We had a problem with our server. Please try again later
503 Service Unavailable We are temporarily offline for maintenance. Please try again later
{
  "status": 404,
  "error": "error message here"
}

Headers

There are quite a few custom response headers available when making a request. Some of these will only show up when the results are paginated.

  1. Link: Link headers with prev, last, next, first links (when appropriate)
  2. Page-Size: The page size for the request
  3. Count: The number of elements returned
  4. Total-Count: The total number of elements (across all pages)
  5. Ratelimit-Limit: The ratelimit for a given user
  6. Ratelimit-Remaining: The number of requests left before the ratelimit is exceeded.
HTTP/1.1 200 Ok
Link: <http://api.magicthegathering.io/v1/cards?page=311>; rel="last", <http://api.magicthegathering.io/v1/cards?page=2>; rel="next"
Page-Size: 100
Count: 100
Total-Count: 31090
Ratelimit-Limit: 5000
Ratelimit-Remaining: 4999

/cards

Get All Cards

This call will return a maximum of 100 cards

Paginate the response using the page parameter.

Each field below can be used as a query parameter. By default, fields that have a singular value such as rarity, set, and name will always use a logical “or” operator when querying with a list of values. Fields that can have multiple values such as colors, supertypes, and subtypes can use a logical “and” or a logical “or” operator.

The accepted delimiters when querying fields are the pipe character or a comma character. The pipe represents a logical “or”, and a comma represents a logical “and”. The comma can only be used with fields that accept multiple values (like colors).

Example:name=nissa, worldwaker|jace|ajani, caller More examples: colors=red,white,blue versus colors=red|white|blue

Parameters
name
The card name. For split, double-faced and flip cards, just the name of one side of the card. Basically each ‘sub-card’ has its own record.
layout
The card layout. Possible values: normal, split, flip, double-faced, token, plane, scheme, phenomenon, leveler, vanguard, aftermath
cmc
Converted mana cost. Always a number
colors
The card colors. Usually this is derived from the casting cost, but some cards are special (like the back of dual sided cards and Ghostfire).
colorIdentity
The card’s color identity, by color code. [“Red”, “Blue”] becomes [“R”, “U”]. A card’s color identity includes colors from the card’s rules text.
type
The card type. This is the type you would see on the card if printed today. Note: The dash is a UTF8 ‘long dash’ as per the MTG rules
supertypes
The supertypes of the card. These appear to the far left of the card type. Example values: Basic, Legendary, Snow, World, Ongoing
types
The types of the card. These appear to the left of the dash in a card type. Example values: Instant, Sorcery, Artifact, Creature, Enchantment, Land, Planeswalker
subtypes
The subtypes of the card. These appear to the right of the dash in a card type. Usually each word is its own subtype. Example values: Trap, Arcane, Equipment, Aura, Human, Rat, Squirrel, etc.
rarity
The rarity of the card. Examples: Common, Uncommon, Rare, Mythic Rare, Special, Basic Land
set
The set the card belongs to (set code).
setName
The set the card belongs to.
text
The oracle text of the card. May contain mana symbols and other symbols.
flavor
The flavor text of the card.
artist
The artist of the card. This may not match what is on the card as MTGJSON corrects many card misprints.
number
The card number. This is printed at the bottom-center of the card in small text. This is a string, not an integer, because some cards have letters in their numbers.
power
The power of the card. This is only present for creatures. This is a string, not an integer, because some cards have powers like: “1+*”
toughness
The toughness of the card. This is only present for creatures. This is a string, not an integer, because some cards have toughness like: “1+*”
loyalty
The loyalty of the card. This is only present for planeswalkers.
language
The language the card is printed in. Use this parameter along with the name parameter when searching by foreignName
gameFormat
The game format, such as Commander, Standard, Legacy, etc. (when used, legality defaults to Legal unless supplied)
legality
The legality of the card for a given format, such as Legal, Banned or Restricted.
page
The page of data to request
pageSize
The amount of data to return in a single request. The default (and max) is 100.
orderBy
The field to order by in the response results
random
Fetch any number of cards (controlled by pageSize) randomly
contains
Filter cards based on whether or not they have a specific field available (like imageUrl)
id
A unique id for this card. It is made up by doing an SHA1 hash of setCode + cardName + cardImageName
multiverseid
The multiverseid of the card on Wizard’s Gatherer web page. Cards from sets that do not exist on Gatherer will NOT have a multiverseid. Sets not on Gatherer are: ATH, ITP, DKM, RQS, DPA and all sets with a 4 letter code that starts with a lowercase ‘p’.

Other Fields in Response

The fields below are also part of the response (if not null), but cannot currently be used as query parameters

Parameters
names
Only used for split, flip and dual cards. Will contain all the names on this card, front or back
manaCost
The mana cost of this card. Consists of one or more mana symbols. (use cmc and colors to query)
variations
If a card has alternate art (for example, 4 different Forests, or the 2 Brothers Yamazaki) then each other variation’s multiverseid will be listed here, NOT including the current card’s multiverseid.
imageUrl
The image url for a card. Only exists if the card has a multiverse id.
watermark
The watermark on the card. Note: Split cards don’t currently have this field set, despite having a watermark on each side of the split card.
border
If the border for this specific card is DIFFERENT than the border specified in the top level set JSON, then it will be specified here. (Example: Unglued has silver borders, except for the lands which are black bordered)
timeshifted
If this card was a timeshifted card in the set.
hand
Maximum hand size modifier. Only exists for Vanguard cards.
life
Starting life total modifier. Only exists for Vanguard cards.
reserved
Set to true if this card is reserved by Wizards Official Reprint Policy
releaseDate
The date this card was released. This is only set for promo cards. The date may not be accurate to an exact day and month, thus only a partial date may be set (YYYY-MM-DD or YYYY-MM or YYYY). Some promo cards do not have a known release date.
starter
Set to true if this card was only released as part of a core box set. These are technically part of the core sets and are tournament legal despite not being available in boosters
rulings
The rulings for the card. An array of objects, each object having ‘date’ and ‘text’ keys.
foreignNames
Foreign language names for the card, if this card in this set was printed in another language. An array of objects, each object having ‘language’, ‘name’ and ‘multiverseid’ keys. Not available for all sets.
printings
The sets that this card was printed in, expressed as an array of set codes.
originalText
The original text on the card at the time it was printed. This field is not available for promo cards.
originalType
The original type on the card at the time it was printed. This field is not available for promo cards.
legalities
Which formats this card is legal, restricted or banned in. An array of objects, each object having ‘format’ and ‘legality’.
source
For promo cards, this is where this card was originally obtained. For box sets that are theme decks, this is which theme deck the card is from.
require 'mtg_sdk'

# Get all Cards
cards = MTG::Card.all

# Filter Cards
# You can chain 'where' clauses together. The key of the hash
# should be the URL parameter you are trying to filter on
cards = MTG::Card.where(supertypes: 'legendary')
                 .where(types: 'creature')
                 .where(colors: 'red,white')
                 .all

# Get cards on a specific page / pageSize
cards = MTG::Card.where(page: 50).where(pageSize: 50).all
from mtgsdk import Card

# Get all cards
cards = Card.all()

# Filter Cards
# You can chain 'where' clauses together. The key of the hash
# should be the URL parameter you are trying to filter on
cards = Card.where(supertypes='legendary') \
            .where(types='creature') \
            .where(colors='red,white') \
            .all()

# Get cards on a specific page / pageSize
cards = Card.where(page=50).where(pageSize=50).all()
const mtg = require('mtgsdk')

// Get all cards
mtg.card.all()
.on('data', function (card) {
  console.log(card.name)
});

// Filter Cards
mtg.card.all({ supertypes: 'legendary', types: 'creature', colors: 'red,white' })
.on('data', function (card) {
    console.log(card.name)
});

// Get cards on a specific page / pageSize
mtg.card.where({ page: 50, pageSize: 50})
.then(cards => {
    console.log(cards[0].name)
})
# Get all cards
curl "https://api.magicthegathering.io/v1/cards"

# Filter cards
curl "https://api.magicthegathering.io/v1/cards?supertypes=legendary&types=creature&colors=red,white"

# Get specific page of data
curl "https://api.magicthegathering.io/v1/cards?page=50&pageSize=50"
{  
  "cards":[  
      {  
      "name":"Archangel Avacyn",
      "names":[  
          "Archangel Avacyn",
          "Avacyn, the Purifier"
      ],
      "manaCost":"{3}{W}{W}",
      "cmc":5,
      "colors":[  
          "White"
      ],
      "colorIdentity":[
          "W"
      ],
      "type":"Legendary Creature — Angel",
      "supertypes":[  
          "Legendary"
      ],
      "types":[  
          "Creature"
      ],
      "subtypes":[  
          "Angel"
      ],
      "rarity":"Mythic Rare",
      "set":"SOI",
      "text":"Flash\nFlying, vigilance\nWhen Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn.\nWhen a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep.",
      "artist":"James Ryman",
      "number":"5a",
      "power":"4",
      "toughness":"4",
      "layout":"double-faced",
      "multiverseid":409741,
      "imageUrl":"http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=409741&type=card",
      "rulings":[  
          {  
          "date":"2016-04-08",
          "text":"Archangel Avacyn’s delayed triggered ability triggers at the beginning of the next upkeep regardless of whose turn it is."
          },
          {  
          "date":"2016-04-08",
          "text":"Archangel Avacyn’s delayed triggered ability won’t cause it to transform back into Archangel Avacyn if it has already transformed into Avacyn, the Purifier, perhaps because several creatures died in one turn."
          },
          {  
          "date":"2016-04-08",
          "text":"For more information on double-faced cards, see the Shadows over Innistrad mechanics article (http://magic.wizards.com/en/articles/archive/feature/shadows-over-innistrad-mechanics)."
          }
      ],
      "foreignNames":[  
          {  
          "name":"大天使艾维欣",
          "language":"Chinese Simplified",
          "multiverseid":410071
          },
          {  
          "name":"大天使艾維欣",
          "language":"Chinese Traditional",
          "multiverseid":410401
          },
          {  
          "name":"Archange Avacyn",
          "language":"French",
          "multiverseid":411061
          },
          {  
          "name":"Erzengel Avacyn",
          "language":"German",
          "multiverseid":410731
          },
          {  
          "name":"Arcangelo Avacyn",
          "language":"Italian",
          "multiverseid":411391
          },
          {  
          "name":"大天使アヴァシン",
          "language":"Japanese",
          "multiverseid":411721
          },
          {  
          "name":"대천사 아바신",
          "language":"Korean",
          "multiverseid":412051
          },
          {  
          "name":"Arcanjo Avacyn",
          "language":"Portuguese (Brazil)",
          "multiverseid":412381
          },
          {  
          "name":"Архангел Авацина",
          "language":"Russian",
          "multiverseid":412711
          },
          {  
          "name":"Arcángel Avacyn",
          "language":"Spanish",
          "multiverseid":413041
          }
      ],
      "printings":[  
          "SOI"
      ],
      "originalText":"Flash\nFlying, vigilance\nWhen Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn.\nWhen a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep.",
      "originalType":"Legendary Creature — Angel",
      "id":"02ea5ddc89d7847abc77a0fbcbf2bc74e6456559"
      },
      { ... },
      { ... }
  ]
  }

/cards/:id

Get Card

Returns a specific card by id or multiverseid

require 'mtg_sdk'

card = MTG::Card.find(386616)
from mtgsdk import Card

card = Card.find(386616)
const mtg = require('mtgsdk')

mtg.card.find(386616)
.then(result => {
    console.log(result.card.name)
})
curl "https://api.magicthegathering.io/v1/cards/386616"
{  
  "card":{  
    "name":"Narset, Enlightened Master",
    "manaCost":"{3}{U}{R}{W}",
    "cmc":6,
    "colors":[  
      "White",
      "Blue",
      "Red"
    ],
    "type":"Legendary Creature — Human Monk",
    ...
  }
}

/sets

Get All Sets

Currently, only the name and block fields can be used as query parameters. To query on multiple names or blocks at a time, use a pipe separated list (ex. sets?name=khans|origins).

Parameters
name
The name of the set
block
The block the set is in

Other Fields In Reponse

The fields below are also part of the response (if not null), but cannot be used as query parameters.

Parameters
code
The code name of the set
gathererCode
The code that Gatherer uses for the set. Only present if different than ‘code’
oldCode
An old style code used by some Magic software. Only present if different than ‘gathererCode’ and ‘code’
magicCardsInfoCode
The code that magiccards.info uses for the set. Only present if magiccards.info has this set
releaseDate
When the set was released (YYYY-MM-DD). For promo sets, the date the first card was released
border
The type of border on the cards, either “white”, “black” or “silver”
expansion
Type of set. One of: “core”, “expansion”, “reprint”, “box”, “un”, “from the vault”, “premium deck”, “duel deck”, “starter”, “commander”, “planechase”, “archenemy”, “promo”, “vanguard”, “masters”
onlineOnly
Present and set to true if the set was only released online
booster
Booster contents for this set
require 'mtg_sdk'

# Get all Sets
sets = MTG::Set.all

# Filter Sets
sets = MTG::Set.where(name: 'khans').all

# Get sets on a specific page / pageSize
sets = MTG::Set.where(page: 2).where(pageSize: 10).all
from mtgsdk import Set

# Get all Sets
sets = Set.all()

# Filter Sets
sets = Set.where(name='khans').all()

# Get sets on a specific page / pageSize
sets = Set.where(page=2).where(pageSize=10).all()
# Get all sets
curl "https://api.magicthegathering.io/v1/sets"

# Filter cards
curl "https://api.magicthegathering.io/v1/sets?name=khans"

# Get specific page of data
curl "https://api.magicthegathering.io/v1/sets?page=2&pageSize=10"
  {  
  "sets":[  
      {  
      "code":"KTK",
      "name":"Khans of Tarkir",
      "type":"expansion",
      "border":"black",
      "mkm_id":1495,
      "booster":[  
          [  
          "rare",
          "mythic rare"
          ],
          "uncommon",
          "uncommon",
          "uncommon",
          "common",
          "common",
          "common",
          "common",
          "common",
          "common",
          "common",
          "common",
          "common",
          "common",
          "land",
          "marketing"
      ],
      "mkm_name":"Khans of Tarkir",
      "releaseDate":"2014-09-26",
      "magicCardsInfoCode":"ktk",
      "block":"Khans of Tarkir"
      },
      { ... }.
      { ... }
  ]
  }

/sets/:id

Get Set

Returns a specific set by the set code

require 'mtg_sdk'

card = MTG::Set.find('ktk')
from mtgsdk import Set

card = Set.find('ktk')
curl "https://api.magicthegathering.io/v1/sets/ktk"
{  
  "set":{  
      "code":"KTK",
      "name":"Khans of Tarkir",
      "type":"expansion",
      "border":"black",
      "mkm_id":1495,
      "booster":[  
      [  
          "rare",
          "mythic rare"
      ],
      "uncommon",
      "uncommon",
      "uncommon",
      "common",
      "common",
      "common",
      "common",
      "common",
      "common",
      "common",
      "common",
      "common",
      "common",
      "land",
      "marketing"
      ],
      "mkm_name":"Khans of Tarkir",
      "releaseDate":"2014-09-26",
      "magicCardsInfoCode":"ktk",
      "block":"Khans of Tarkir"
  }
}

/sets/:id/booster

Generate Booster Pack

Returns a list of cards for a specific set representing a booster pack for the set. The number of commons, uncommons, rares, etc. are determined by the booster field in a set response.

require 'mtg_sdk'

card = MTG::Set.generate_booster('ktk')
from mtgsdk import Set
from mtgsdk import Card

card = Set.generate_booster('ktk')
curl "https://api.magicthegathering.io/v1/sets/ktk/booster"
{
  "cards": [
      {
      "name": "Meandering Towershell",
      "manaCost": "{3}{G}{G}",
      "cmc": 5,
      "colors": [
          "Green"
      ],
      "type": "Creature — Turtle",
      "types": [
          "Creature"
      ],
      "subtypes": [
          "Turtle"
      ],
      ...
      }
  ]
}

/types

Get All Types

require 'mtg_sdk'

types = MTG::Type.all
from mtgsdk import Type

types = Type.all()
curl "https://api.magicthegathering.io/v1/types"
{  
  "types":[  
    "Artifact",
    "Conspiracy",
    "Creature",
    "Enchantment",
    "Instant",
    "Land",
    "Phenomenon",
    "Plane",
    "Planeswalker",
    "Scheme",
    "Sorcery",
    "Tribal",
    "Vanguard"
  ]
}

/subtypes

Get All Sub Types

require 'mtg_sdk'

subtypes = MTG::Subtype.all
from mtgsdk import Subtype

subtypes = Subtype.all()
curl "https://api.magicthegathering.io/v1/subtypes"
{  
  "subtypes":[  
    "Advisor",
    "Ajani",
    "Alara",
    "Ally",
    "Angel",
    "Antelope",
    "Ape",
    "Arcane"
  ]
}

/supertypes

Get All Super Types

require 'mtg_sdk'

supertypes = MTG::Supertype.all
from mtgsdk import Supertype

supertypes = Supertype.all()
curl "https://api.magicthegathering.io/v1/supertypes"
{  
  "supertypes":[  
    "Basic",
    "Legendary",
    "Ongoing",
    "Snow",
    "World"
  ]
}

/formats

Get All Game Formats

{
  "formats": [
    "Amonkhet Block",
    "Battle for Zendikar Block",
    "Classic",
    "Commander",
    "Extended",
    "Freeform",
    "Ice Age Block",
    "Innistrad Block",
    "Invasion Block",
    "Kaladesh Block",
    "Kamigawa Block",
    "Khans of Tarkir Block",
    "Legacy",
    "Lorwyn-Shadowmoor Block",
    "Masques Block",
    "Mirage Block",
    "Mirrodin Block",
    "Modern",
    "Odyssey Block",
    "Onslaught Block",
    "Prismatic",
    "Ravnica Block",
    "Return to Ravnica Block",
    "Scars of Mirrodin Block",
    "Shadows over Innistrad Block",
    "Shards of Alara Block",
    "Singleton 100",
    "Standard",
    "Tempest Block",
    "Theros Block",
    "Time Spiral Block",
    "Tribal Wars Legacy",
    "Un-Sets",
    "Urza Block",
    "Vintage",
    "Zendikar Block"
  ]
}

Find by foreign name

Get Cards by Foriegn Name

Returns cards by name

require 'mtg_sdk'

cards = MTG::Card.where(name: 'Arcángel Avacyn')
                 .where(language: 'spanish')
                 .all
from mtgsdk import Card

cards = Card.where(name='Arcángel Avacyn')
            .where(language='spanish')
            .all()
const mtg = require('mtgsdk')

mtg.card.where({name: 'Arcángel Avacyn', language: 'spanish'})
.then(results => {
    console.log(results)
})
curl "https://api.magicthegathering.io/v1/cards?name=Arcángel Avacyn&language=spanish"
{  
  "cards":[  
      {  
      "name":"Archangel Avacyn",
      "names":[  
          "Archangel Avacyn",
          "Avacyn, the Purifier"
      ],
      "manaCost":"{3}{W}{W}",
      "cmc":5,
      ...
  ]
  }

Find by name

Get Cards by Name

Returns cards by name

require 'mtg_sdk'

# partial name match
cards = MTG::Card.where(name: 'avacyn').all

# exact name mtch
cards = MTG::Card.where(name: '"Archangel Avacyn"').all
from mtgsdk import Card

# partial name match
cards = Card.where(name='avacyn').all()

# exact name match
cards = Card.where(name='"Archangel Avacyn"').all()
const mtg = require('mtgsdk')

// partial name match
mtg.card.where({name: 'Archangel Avacyn'})
.then(results => {
    console.log(results)
})

// exact name match
mtg.card.where({name: '"Archangel Avacyn"'})
.then(results => {
    console.log(results)
})
# partial name match
curl "https://api.magicthegathering.io/v1/cards?name=avacyn"

# exact name match
curl 'https://api.magicthegathering.io/v1/cards?name="Archangel Avacyn"'
{  
  "cards":[  
      {  
      "name":"Archangel Avacyn",
      "names":[  
          "Archangel Avacyn",
          "Avacyn, the Purifier"
      ],
      "manaCost":"{3}{W}{W}",
      "cmc":5,
      ...
  ]
  }