"""A trading card game supported by TCGGraph.""" enum Game { POKEMON MAGIC_THE_GATHERING ONE_PIECE YUGIOH DISNEY_LORCANA STAR_WARS_UNLIMITED DIGIMON GRAND_ARCHIVE DRAGON_BALL_SUPER } enum CardSort { NAME NAME_DESC PRICE PRICE_DESC """ By one slot of the graded index: the filter's grader and grade, PSA 10 when unset. """ GRADED_PRICE GRADED_PRICE_DESC RELEASED RELEASED_DESC } type Set { code: String! name: String! """ The set's own language: EN for an English set whatever language the printing is, JA for an own-language set (Japanese Pokémon), whose codes can repeat an English set's -- the Japanese sv3 is not the English sv3. """ language: Language! releasedAt: String } type Images { small: String normal: String large: String } """ Perceptual hashes of the card's artwork, for matching a photograph or a scan against the catalogue. Null until the artwork has been processed. Compare two hashes by Hamming distance. Read them together: 'phash' describes structure and survives the colour cast and exposure a camera introduces, but is blind to printings that differ only in colour. 'phashColor' sees exactly that difference, so it breaks the ties 'phash' cannot. """ type Hashes { """64-bit DCT hash of the artwork's luma, as 16 hex characters.""" phash: String! """192-bit colour hash, white-balance corrected, as 48 hex characters.""" phashColor: String } """A marketplace we quote prices from.""" enum PriceSource { """ Cardmarket, the European market. Quotes in EUR. Every game but Grand Archive, which Cardmarket does not list. """ CARDMARKET """ TCGplayer, the North American market. Quotes in USD. Every game; Magic by way of MTGJSON, the rest read from TCGplayer's daily publication. """ TCGPLAYER """ Card Kingdom, a North American dealer. Quotes in USD, retail and buylist. Magic only. """ CARDKINGDOM """Manapool, a North American marketplace. Quotes in USD. Magic only.""" MANAPOOL } """ Which side of the market a price is. A retail price is what a buyer pays for the card. A buylist price is what the dealer pays to buy it from you, and is always the lower of the two. They are different markets and are never mixed within a series. """ enum ListType { RETAIL BUYLIST } enum PriceRegion { NA EU } """ One quote, from one marketplace, for one finish. A card carries a row per finish, so a foil and a nonfoil are priced as the separate products they are. """ type Price { source: PriceSource! region: PriceRegion! """Retail unless asked otherwise. Only Card Kingdom publishes a buylist.""" listType: ListType! finish: String! """ISO-4217 code. EUR on Cardmarket.""" currency: String! """ The headline quote: the trend price where the marketplace publishes one, else the plain average. """ market: Float """ Cheapest live article, in any condition and any language. For one language, see 'languagePrices'. """ low: Float """ The marketplace's own smoothed price, and what European sellers anchor to. """ trend: Float """Mean of the last day's sales.""" avg1: Float """Mean of the last seven days.""" avg7: Float """Mean of the last thirty days.""" avg30: Float """ Cardmarket only: where these figures were read. 'product-page' is the summary on the product's page as our crawl read it at 'updatedAt'; 'price-guide' is Cardmarket's daily price guide file. Null on the other marketplaces. """ basis: String """When this quote was last read from the marketplace. ISO 8601.""" updatedAt: String! } """ Why a card does or does not carry a Cardmarket quote. An empty 'prices' on its own cannot tell "Cardmarket does not sell this" from "not priced yet"; this can. """ enum CardmarketStatus { """ A Cardmarket product is identified and quoted. The quote is on prices[]. """ PRICED """ The product is identified but Cardmarket publishes no usable quote for it yet, which is typical of a new release before its first sales. """ UNQUOTED """ Cardmarket lists several products under this name in the expansion this printing belongs to, and nothing it publishes says which one is this printing. We do not guess. """ AMBIGUOUS """ Every candidate product under this name is identified as another printing of the same card, so none is left for this one. Those printings carry their quotes; this variant does not. """ COLLAPSED """ The expansion this printing belongs to is on Cardmarket but no product there carries this card's name and number. """ UNLISTED """ Cardmarket has no expansion for this set, or none we could identify with confidence, so nothing in it can be priced. """ SET_UNLISTED """Cardmarket does not carry this game.""" GAME_UNLISTED } """ Who graded the copy a quote is for. RAW is an ungraded copy. ANY is a grade quoted across grading companies rather than for one of them: the market does not separate a PSA 8 from a BGS 8 closely enough to publish them apart. The named companies are told apart only at grade 10. """ enum Grader { RAW ANY PSA BGS CGC SGC } """ The grade on the slab. UNGRADED goes with RAW; the rest with the graders above. """ enum Grade { UNGRADED G7 G8 G9 G9_5 G10 } """ What a graded copy of this printing sells for, from tcggraph's graded index. USD, refreshed daily from recorded sales of slabs. """ type GradedPrice { grader: Grader! grade: Grade! """ISO-4217 code. USD.""" currency: String! price: Float! """Units of this printing sold in the last year, all grades together.""" salesVolume: Int updatedAt: String! } """ Why a card does or does not carry graded quotes. Same words as CardmarketStatus. """ enum GradedStatus { """ This printing is identified in the graded index and quoted. The quotes are on gradedPrices[]. """ PRICED """ The printing is identified in the graded index but no grade has enough recorded sales to quote yet, which is typical of a new release. """ UNQUOTED """ The graded index lists several products under this name and number in this set and nothing distinguishes which is this printing. We do not guess. """ AMBIGUOUS """ This printing shares its only candidate in the graded index with another printing of the same card. The base printing carries the quotes; this variant does not. """ COLLAPSED """ The set is in the graded index but no product there carries this card's name and number. """ UNLISTED """ The graded index has no entry for this set, or none we could identify with confidence, so nothing in it can be quoted. """ SET_UNLISTED """The graded index does not cover this game.""" GAME_UNLISTED } """ Why a card does or does not carry a TCGplayer quote. Same words as CardmarketStatus. Null for Magic, which is priced from MTGJSON. """ enum TcgplayerStatus { """ A TCGplayer product is identified and quoted. The quote is on prices[]. """ PRICED """ The product is identified but TCGplayer publishes no market or low price for it yet, which is typical of a new release before its first sales. """ UNQUOTED """ TCGplayer lists several products under this number in this set and neither their names nor their images settle which one is this printing. We do not guess. """ AMBIGUOUS """ The set is on TCGplayer but no product there carries this card's number. """ UNLISTED """ TCGplayer has no set matching this one, or none we could identify with confidence, so nothing in it can be priced. """ SET_UNLISTED } """ Cardmarket lows split by language: what the cheapest copy in English, German, Japanese and so on is selling for right now. Cardmarket's own price guide carries no language, so 'Price.low' is the cheapest copy in any language; these rows are per language. EUR. A card has no rows until its language data is available, and a row with zero offers is a real answer: nothing for sale in that language. """ type LanguagePrice { source: PriceSource! language: Language! """ The same closed list 'Price.finish' uses, and the same word for the same printing: an unmarked listing of a holo rare is 'foil' as its guide quote is, a Reverse Holo listing is 'reverse-holo'. """ finish: String! """ISO-4217 code. EUR.""" currency: String! """ Cheapest live article in this language, any condition. Null when none is for sale. """ low: Float """Cheapest Near Mint or Mint article in this language.""" lowNm: Float """Median asking price of the cheapest offers in this language.""" market: Float """Live articles counted in this language.""" offers: Int! """ True when only the cheapest 50 articles overall were counted, so dearer copies in this language may exist beyond them. """ truncated: Boolean! """ On a truncated row, the dearest price that was seen. A condition missing from 'conditions' has no copy at or below it; above it is unknown. Null when the read was complete. """ truncatedAbove: Float """ Cheapest copy per condition, best first, optionally one condition. Only conditions with a live article appear; on a truncated row a missing one may still be for sale above 'truncatedAbove'. """ conditions(condition: Condition): [ConditionPrice!]! """When this row was last updated.""" updatedAt: String! } """ Cardmarket's condition ladder, best first. Roughly TCGplayer's NM, LP, MP, HP and DMG: MT and NM are Near Mint, EX and GD Lightly Played, LP and PL Moderately to Heavily Played, PO Damaged. """ enum Condition { MT NM EX GD LP PL PO } type ConditionPrice { condition: Condition! """Cheapest live article in this language, finish and condition. EUR.""" low: Float! """Live articles counted in this condition.""" offers: Int! } """One day's realized sales on Cardmarket.""" type SalePoint { """YYYY-MM-DD.""" day: String! """Average price copies actually sold for that day.""" avgSell: Float! } """ What copies actually sold for, by day: the realized price, not an asking price and not the guide. Every language and condition together, as Cardmarket publishes it; on a product sold in two versions (a foil switch on its page), the plain version's, with the other under the finish `foil` or `reverse-holo`. Days with no sale have no point. The series starts about 30 sale days before the card entered our coverage (a month for a card that sells daily, longer for one that rarely does) and grows from there. For Pokémon, Yu-Gi-Oh!, Dragon Ball Super and One Piece, archived copies of the product page (2018 to 2023) add older windows, with a gap before our first read. """ type SalesHistory { """ISO-4217 code. EUR.""" currency: String! """Oldest first.""" sales: [SalePoint!]! } """ What kind of variation a finish is. SURFACE is how the card face is treated (foil, reverse holo); PATTERN a foil pattern printed across the card (Poké Ball, Master Ball); STAMP a mark added for an event (Staff, Prerelease, League); EDITION a print run (1st Edition, Shadowless). """ enum FinishKind { SURFACE PATTERN STAMP EDITION } """ Where a printing's picture comes from: its own product photo, or the card's picture when it has none. """ enum ImageFrom { PRINTING CARD } """ The marketplace products a printing's quotes are read from. Null where a marketplace has none for it. """ type PrintingExternalIds { cardmarketId: Int tcgplayerId: Int } """ One physical way the card was produced: a finish with a label, the picture that shows it and its quotes. 'prices' regrouped by 'finish', so a Poké Ball pattern, a Staff stamp or a Shadowless print is its own entry with its own picture and its own quotes. 'key' is stable across re-resolution; key user selections on it. After the card's own finishes come its stamped and holo reprints sold as products of their own (Pokémon: the GameStop and EB Games exclusives, Prize Pack, Trick or Trade), each keyed by its record's id. """ type Printing { """ The 'finish' value, one of the closed finish vocabulary (see /docs/prices); for a reprint sold as a product of its own, that record's id. """ key: String! """ Human label: 'Holofoil', 'Poké Ball pattern', 'Shadowless', 'GameStop Exclusive', 'Trick or Trade 2024'. """ label: String! kind: FinishKind! """ The printing's own picture where a marketplace shows one; the card's otherwise. """ images: Images! imageFrom: ImageFrom! externalIds: PrintingExternalIds! """ This printing's quotes, one per source. A reprint's may span several finishes, each quote naming its own. """ prices: [Price!]! """ The card 'prices' are kept on: the id price history and sales are asked for under. """ cardId: ID! } type PriceStatus { """Null only for a card no price run has considered yet.""" cardmarket: CardmarketStatus """Null for a card no TCGplayer run has considered yet, and for Magic.""" tcgplayer: TcgplayerStatus """Null only for a card the graded index has not considered yet.""" graded: GradedStatus } """ The language a printing is in. Codes follow Scryfall: ZHS is simplified Chinese, ZHT traditional. Yu-Gi-Oh's JP and KR and its SP are JA, KO and ES. """ enum Language { EN DE FR IT ES PT JA KO RU ZHS ZHT TH ID PH QYA DW GRC HE AR LA SA } """ Whose quotes a card's 'prices', 'gradedPrices' and 'priceStatus' are. OWN for a printing quoted in its own right -- an English printing, an own-language set, or a localized printing bound to a marketplace product of its own, as Japanese One Piece is on Cardmarket; ENGLISH_TWIN for a localized printing served its English twin's quotes, because the marketplaces sell that product across languages and we do not invent a per-language figure; LOCALIZED_TWIN for an English printing no marketplace sells in English, served the quotes of its twin in another language, named on 'pricesTwin' (a Japan-only One Piece promo, priced as the Japanese copy). """ enum PricesFrom { OWN ENGLISH_TWIN LOCALIZED_TWIN } """ Whose picture a card's 'images' is. OWN for the printing's scan; ENGLISH_TWIN for a localized printing in an English set its source has no scan of (older European Pokémon, Magic printings Scryfall shows in English only), shown its English twin's picture. Such a card has no 'hashes' and recognition never answers it. """ enum CardImageFrom { OWN ENGLISH_TWIN } """ The printing an English card's quotes are from, with LOCALIZED_TWIN, and the language its copies are in. """ type PricesTwin { id: ID! language: Language! } """ Core fields are identical for every game. Game-specific stats live in `gameData`, whose shape is declared by `Game.schema`. One row per printing per language. 'name' is always the English name, so a Japanese printing and its English twin are found by the same search; the name as printed is 'printedName'. """ type Card { id: ID! game: Game! """The English name, on every language's printing.""" name: String! language: Language! """The name as printed on the card. Null on English printings.""" printedName: String """ The English printing this one corresponds to: the same set and number for a localized twin in an English set; the same illustration, by artwork hash, for a card in an own-language set (Japanese Pokémon), whose set and number differ. Null on English rows and where none is found. """ englishId: ID """ The printings of this card's illustration in the other catalogue, linked by artwork (Japanese Pokémon): on a Japanese card every English printing of the picture, reprints included, nearest first (englishId is the first); on an English card the Japanese printings of it. Empty where none is found and on games whose languages share set and number. """ sameArtwork: [ID!]! """ The card this record reprints, for a Pokémon card sold as a product of its own outside the expansions: a stamped store exclusive, a Prize Pack or World Championship deck copy. Null elsewhere and where the base could not be told for certain. """ baseCardId: ID pricesFrom: PricesFrom! """ With LOCALIZED_TWIN, the printing quoted and its language. Null otherwise. """ pricesTwin: PricesTwin set: Set! collectorNumber: String! rarity: String! artist: String text: String images: Images! imageFrom: CardImageFrom! hashes: Hashes prices: [Price!]! """ The card's printings: 'prices' regrouped by finish, each with its label, picture and products. Plain card first; stamped and holo reprints sold as products of their own last. """ printings: [Printing!]! """ Graded quotes for this printing. Both arguments or neither: one slot, or every slot held. """ gradedPrices(grader: Grader, grade: Grade): [GradedPrice!]! """ Cardmarket lows by language, optionally one language. Empty until language data is available for this card. """ languagePrices(language: Language): [LanguagePrice!]! """ Realized Cardmarket sales by day over the last 'days' days (90 by default, 7305 at most). 'finish' asks for a printing Cardmarket sells as its own product (a Master Ball pattern, a stamp). Empty in the playground. """ sales(days: Int, finish: String): SalesHistory! priceStatus: PriceStatus! legalities: JSON! gameData: JSON! } type PageInfo { page: Int! limit: Int! totalCount: Int! totalPages: Int! hasMore: Boolean! """Which marketplace the price filters and the price sort ran against.""" priceSource: PriceSource! } type CardConnection { nodes: [Card!]! pageInfo: PageInfo! } type SchemaField { name: String! type: String! description: String! } type GameInfo { slug: String! name: String! shortName: String! publisher: String! released: Int! languages: [String!]! formats: [String!]! sampleCount: Int! schema: [SchemaField!]! } input CardFilter { game: Game """ Part of the English name or of the name as printed: 'dracaufeu' with language FR, 'ルフィ' with JA on One Piece. Case, accents and punctuation are ignored. """ name: String text: String rarity: String set: String """ The number printed on the card, loosely: 6, 006 and 006/165 are the same card. Pair with `set` for one printing. """ collectorNumber: String artist: String """ Which language's printings. English when omitted, so a query that never mentions language sees one row per printing as before. Set `allLanguages` instead to get every language, one row each. """ language: Language """ Every language, one row per printing per language. Overrides `language`. """ allLanguages: Boolean """ Which marketplace `minPrice`, `maxPrice` and the price sort read from. Defaults to `CARDMARKET`. Bounds are in that source's currency, so `{ source: TCGPLAYER, minPrice: 50 }` means $50, not €50. """ source: PriceSource minPrice: Float maxPrice: Float """ Which slot of the graded index `GRADED_PRICE` sorts on. Both or neither; PSA 10 when neither. """ grader: Grader grade: Grade """ Filter on game-specific fields, e.g. `{ hp: 330 }` or `{ types: "Fire" }`. A value matches a scalar field exactly (case-insensitively) or a member of a list field. Dotted paths reach into object fields; pass them through a variable, since `banlist.tcg` is not a GraphQL name. """ gameData: JSON """ Inclusive lower bounds on numeric game fields, e.g. `{ hp: 300 }` for hp >= 300. REST spells the same thing `?minHp=300`. """ gameDataMin: JSON """ Inclusive upper bounds on numeric game fields, e.g. `{ manaValue: 3 }`. REST: `?maxManaValue=3`. """ gameDataMax: JSON } type Query { """Look up a single card by its stable TCGGraph id.""" card(id: ID!): Card """Query cards across every game with one filter shape.""" cards(filter: CardFilter, sort: CardSort, page: Int, limit: Int): CardConnection! """Every supported game, with counts and its field declaration.""" games: [GameInfo!]! """One game by slug.""" game(slug: String!): GameInfo } scalar JSON