Skip to content
Prepaid, no subscription trap. Top up a balance and we draw the monthly fee from it.
tcggraph

Deck building

Deck builders live or die on legality, not on card text

Build a deck builder with per-format legality, typed game fields and deck costing across eight games from one schema.

The problem

Where this project usually goes wrong

A deck builder is judged on one thing: whether it tells the truth about what is legal. Get a ban list wrong and a user takes an illegal deck to an event. That is the kind of bug people write posts about.

Legality is harder than it looks because it is not one flag. A Yu-Gi-Oh card can be legal in the OCG, limited in the TCG, and forbidden in Master Duel simultaneously. An API that flattens that into a single banned boolean is wrong for at least two of those formats, and you will not find out from the response — it looks perfectly plausible.

The second problem is that every game has different rules to model. Mana value and colour identity mean nothing in One Piece; DON!! attachment means nothing in Magic. Building a deck builder for more than one game with a single generic card shape means writing the game-specific logic yourself, from text parsing, forever.

What it needs

The fields that decide it

legalities per format
Separate status for every format a game has, so a validator can answer the question the user actually asked.
gameData typed per game
Mana value, ink cost, DON!! cost, digivolve requirements — structured fields rather than rules text you have to parse.
Webhooks on legality changes
Ban announcements land without you polling, so decks are revalidated before your users notice.
Reprint linking
A deck is a list of cards, not printings, so the cheapest legal printing can be chosen at costing time.
prices[] on every printing
Deck cost, and the cheaper-printing suggestion that keeps budget players engaged.

In practice

The two queries that matter most

Written for deck construction, legality checking and playtesting tools. Both work the same way for every game we carry.

Validate a decklist against one format

Validate a decklist against one format
curl -G "https://api.tcggraph.com/v1/cards" \
  -d game=yugioh \
  -d "legality.tcg=limited,forbidden" \
  -d limit=200 \
  -H "Authorization: Bearer $TCGGRAPH_KEY"

Pull the restricted list for the format once and cache it, rather than checking cards one at a time. Ban lists are small and change rarely — until they change, which is what the webhook is for.

Cost a deck at its cheapest legal printings

Cost a deck at its cheapest legal printings
{
  cards(filter: { game: MAGIC_THE_GATHERING, name: "Lightning Bolt" }) {
    nodes {
      set { name releasedAt }
      collectorNumber
      finish
      legalities { modern legacy commander }
      prices(source: CARDMARKET) { market currency }
    }
  }
}

Every printing with its own price means the budget build is a sort, not a research project.

Avoid these

Three mistakes that are expensive to undo

Each of these is cheap to get right at the start and painful to retrofit once you have user data shaped the wrong way.

  • Treating legality as a single boolean

    Every game has multiple formats and they disagree. Model legality as a map from format to status, even if you only surface one format today.

  • Polling for ban list changes

    Ban announcements are unpredictable and your poll interval is a guess. A webhook turns a race into a notification.

  • Parsing rules text for structured values

    Costs, types and stats are fields. Reading them out of the text blob works until the first card that words it differently, which is roughly every set.

Questions

Deck builder, answered

Ship your card app this weekend

$19 a month for 25,000 credits, no sales call and no contract. Pick a plan and your first query runs in under a minute.