Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/invvd/mtg-cheaper-deck/llms.txt

Use this file to discover all available pages before exploring further.

The moxfield_client module is the entry point for retrieving deck data from Moxfield. It handles URL parsing, HTTP communication, JSON validation, and conversion of the raw API response into a flat list of card dicts that the rest of the pipeline can consume. All failures — network errors, blocked requests, unexpected response shapes — are surfaced as a single MoxfieldError exception so that callers never need to inspect raw HTTP status codes.
The endpoint https://api2.moxfield.com/v2/decks/all/{deck_id} is unofficial and undocumented. Moxfield can change the response shape, authentication requirements, or URL structure at any time without notice. If the pipeline stops working, call fetch_deck_raw() directly and inspect the response before assuming the endpoint has moved.

Constant

MOXFIELD_API_URL = "https://api2.moxfield.com/v2/decks/all/{deck_id}"
The base URL template for the Moxfield v2 deck endpoint. {deck_id} is substituted at request time by fetch_deck_raw(). A browser-like User-Agent header is sent with every request to reduce the chance of a Cloudflare 403.

MoxfieldError

MoxfieldError is the single exception type raised by every function in this module. It inherits directly from Exception and is used for any failure condition: network timeouts, HTTP errors (403, 404, other non-2xx), and responses that cannot be decoded as JSON.
from moxfield_client import MoxfieldError

try:
    cards = get_moxfield_deck("https://moxfield.com/decks/abc123")
except MoxfieldError as exc:
    print(f"Could not load deck: {exc}")
Catch MoxfieldError at the top of your pipeline to handle all Moxfield-related failures in one place.

extract_deck_id

Extracts the deck ID string from a full Moxfield URL, or passes a bare ID through unchanged.
url_or_id
str
required
A full Moxfield deck URL such as https://moxfield.com/decks/XyZ-abc123 or a bare deck ID such as XyZ-abc123. Leading and trailing whitespace is stripped automatically.
Returns str — the deck ID portion of the URL (the segment that follows /decks/), or the input itself when it contains no / or spaces and is non-empty. Raises MoxfieldError if the input looks like a URL but no deck ID can be found with the pattern moxfield.com/decks/{id}, or if the input is an empty string.
from moxfield_client import extract_deck_id

# From a full URL
deck_id = extract_deck_id("https://moxfield.com/decks/XyZ-abc123")
# "XyZ-abc123"

# Bare ID passed through
deck_id = extract_deck_id("XyZ-abc123")
# "XyZ-abc123"

fetch_deck_raw

Calls the Moxfield API for a given deck and returns the raw, unparsed JSON response as a Python dict.
url_or_id
str
required
A full Moxfield deck URL or a bare deck ID. Passed to extract_deck_id() internally.
timeout
float
default:"15.0"
Request timeout in seconds. Raise for slow connections; lower for interactive use where a fast failure is preferable.
Returns dict — the complete decoded JSON body from the Moxfield API. The exact shape depends on Moxfield’s current response format; use this return value with parse_deck() or inspect it directly when debugging. Raises MoxfieldError in the following situations:
ConditionMessage
Request times out"Timeout llamando a Moxfield (…)"
Any other network error"Error de red llamando a Moxfield: …"
HTTP 403Probable Cloudflare / anti-bot block
HTTP 404Deck not found or not public
Any other non-2xxStatus code + first 300 chars of body
Response is not valid JSON"La respuesta de Moxfield no es JSON válido"
A 403 response almost always means Cloudflare blocked the request, not that the endpoint moved. Try adjusting the User-Agent header before assuming the API URL has changed.
from moxfield_client import fetch_deck_raw

raw = fetch_deck_raw("https://moxfield.com/decks/YOUR-DECK-ID")
print(sorted(raw.keys()))
# Inspect the raw response shape when debugging

parse_deck

Converts a raw Moxfield JSON dict (as returned by fetch_deck_raw()) into a flat list of card entry dicts.
data
dict
required
The raw JSON dict returned by fetch_deck_raw(). The function handles two known response shapes: a top-level commanders / mainboard / companion dict-of-dicts, and a nested boards.{board_name}.cards dict-of-dicts.
Returns list[dict] — a list where each element represents one card entry:
name
str
Card name as returned by Moxfield (e.g. "Sol Ring").
scryfall_id
str | None
The Scryfall printing ID. Tried from card.scryfall_id, then card.scryfallId, then card.id. May be None if the field is absent.
quantity
int
Number of copies in the deck. Defaults to 1 if the field is missing.
board
str
The board the card belongs to: "commanders", "mainboard", or "companion" (for the top-level shape), or whatever key appears under boards in the nested shape.
from moxfield_client import fetch_deck_raw, parse_deck

raw = fetch_deck_raw("https://moxfield.com/decks/YOUR-DECK-ID")
cards = parse_deck(raw)

for card in cards[:3]:
    print(card)
# {'name': 'Sol Ring', 'scryfall_id': 'abc...', 'quantity': 1, 'board': 'mainboard'}

get_moxfield_deck

Convenience wrapper that fetches, parses, and validates a Moxfield deck in a single call. This is the function you should use in most situations.
url_or_id
str
required
A full Moxfield deck URL or bare deck ID. Forwarded to fetch_deck_raw().
timeout
float
default:"15.0"
Request timeout in seconds, forwarded to fetch_deck_raw().
Returns list[dict] — the same structure as parse_deck(), guaranteed to be non-empty. Raises MoxfieldError for all the same reasons as fetch_deck_raw(), plus one additional case: if parse_deck() returns an empty list (indicating that the response was valid JSON but its shape was not recognised), a MoxfieldError is raised with a message advising you to call fetch_deck_raw() and inspect the response manually.
from moxfield_client import get_moxfield_deck, MoxfieldError

try:
    cards = get_moxfield_deck("https://moxfield.com/decks/YOUR-DECK-ID")
except MoxfieldError as exc:
    print(f"Failed: {exc}")
else:
    print(f"Loaded {len(cards)} cards")
    for card in cards:
        print(card["board"], card["quantity"], card["name"])

Build docs developers (and LLMs) love