Back

Gradely Exchange Format

Gradely Exchange Format (GXF)

The Gradely Exchange Format is a simple, human-readable text format for describing lists of cards and sealed products (booster boxes, bundles, precons and the like). It works across all supported TCGs (MTG, Pokemon, One Piece, Flesh and Blood, Sorcery, Riftbound) and is used for importing decks, preconstructed products, and bulk-adding cards and sealed products, including their full acquisition and disposal history, to your collection.

Line Types

A GXF file has four kinds of lines:

LinePrefixDescription
Comment#Ignored entirely
Directive@Sets defaults and metadata
Zone header##Names a zone for subsequent cards
Card linenumberA card entry with quantity (or, inside a @kind sealed block, a sealed product entry)

Directives

Directives set metadata and defaults. File-level directives appear once and describe the file:

DirectiveDescriptionExample
@nameHuman-readable name@name "Eldrazi Unbound"
@typeList type@type precon
@formatGame format@format commander
@releasedRelease date@released 2023-08-04

Block-level directives can be redeclared anywhere. Each declaration changes the default (or, for @kind, the kind of line) for all subsequent lines:

DirectiveDescriptionExample
@kindSwitches subsequent lines between cards and sealed products (default card)@kind sealed
@tcgDefault TCG@tcg mtg
@setDefault set code@set cmm
@tagsTags for subsequent cards@tags precon, eldrazi
@conditionDefault condition, cards only. A sealed value like damaged_packaging is rejected here, use @sealed_condition instead@condition near_mint
@sealed_conditionDefault condition, sealed only. Only sealed or damaged_packaging are accepted, a card value like near_mint is rejected here@sealed_condition damaged_packaging
@finishingDefault finishing@finishing foil
@treatmentDefault treatment@treatment cold_foil

Row-level tags on a card line merge with the active @tags directive; duplicates are removed case-insensitively.

Card Lines

Each card line starts with a quantity, followed by an identifier and optional pipe-delimited fields:

<quantity> <identifier> [| set_code] [| card_number] [| finishing] [| condition] [| treatment] [| tags] [| price] [| date] [| key=value ...]

When the identifier is a gid: or cid:, it already pins the exact printing, so the set_code and card_number fields are dropped and the printing comes first: gid:abc | finishing | condition | treatment | tags | price | date.

Identifier forms:

FormSyntaxMeaning
Card nameSol RingResolve by name (uses @tcg + @set defaults)
TCG-prefixedmtg:Sol RingResolve by name with explicit TCG (overrides @tcg)
Gradely IDgid:abc123Exact card by Gradely ID
Canonical IDcid:abc123Any printing of this card (newest selected)
Sealed product IDsid:8f3a2c14-...Exact sealed product by Gradely product ID (@kind sealed lines only)
Sealed product namesealed:Bloomburrow Collector Booster BoxResolve a sealed product by name (@kind sealed lines only); splits on the first colon only, so a name that itself contains a colon still works. Inside a @kind sealed block a bare name needs no prefix at all

Fields can be skipped by leaving them empty between pipes:

# Just foil, no set or number
1 Sol Ring | | | foil

# Set and number, skip finishing, set condition
1 Sol Ring | cmm | 5 | | lightly_played

# All five fields
1 Enlightened Strike | evr | 027 | foil | near_mint | cold_foil

# Row-level tags applied to this card (merged with any active @tags directive)
1 Sol Ring | cmm | 5 | foil | near_mint | showcase | binder, trade

# Acquisition price and date (collection imports only)
1 Sol Ring | cmm | 5 | foil | near_mint | normal | | AUD:4.20 | 2026-06-27

The last two fields capture what you paid for a card and when, and only apply when importing into your collection (decks ignore them). The price accepts an optional currency and dollar sign, so AUD:4.20, AUD:$4.20, $4.20 and 4.20 are all valid. When you leave the currency off, we use your preferred currency. The date is YYYY-MM-DD. Both are optional, so older files without them keep working unchanged.

Beyond those, a card line can carry named fields, key=value pairs such as notes= or sold_as=, for the full acquisition and disposal history of a copy. See the named fields reference below for the complete list and its rules.

Zone Headers

Use ## to group cards into zones. If no zone header appears, all cards go to the main zone.

## Main Deck
1 Sol Ring
1 Arcane Signet

## Sideboard
1 Rest in Peace

## Commander
1 Zhulodok, Void Gorger

Full Example

@tcg mtg
@name "Eldrazi Unbound"
@type precon
@format commander
@set cmm

## Commander
1 Zhulodok, Void Gorger | cmm | 5

## Main Deck
1 Sol Ring
1 Arcane Signet
1 Ulamog, the Ceaseless Hunger | bfz | 15
1 Thought-Knot Seer | ogw | 9 | foil

## Sideboard
1 Rest in Peace | akh | 18

Supported TCG Values

mtgpokemononepieceriftboundfabsorcerylorcanagundam

Condition Values

mintnear_mintlightly_playedmoderately_playedheavily_playeddamaged

Finishing Values

normalfoiletchedreverse_holo

GXF: importing sealed products

Switch a block from cards to sealed products with the @kind directive, then list your sealed products the same way you list cards, quantity first. Switch back to cards with @kind card (the default). Set a default condition for the whole block with @sealed_condition (sealed or damaged_packaging). This is separate from @condition, which is cards only, the two vocabularies share no values, so each line kind gets its own directive.

<quantity> <identifier> [| condition] [| price] [| date] [| key=value ...]

Identify a sealed product one of three ways: sid:<product-id> pins an exact catalogue product, sealed:<name> names one inline, or inside a @kind sealed block, a bare name needs no prefix at all. See the identifier table above for the exact syntax.

Worked example:

@tcg mtg
@kind sealed
2 Bloomburrow Collector Booster Box | sealed | AUD:280.00 | 2026-08-01 | intent=investment | fees=AUD:12.50
1 sid:8f3a2c14-9b7e-4d51-a0c6-2e5f8b1d3a97 | damaged_packaging | AUD:95.00 | 2026-07-14
1 Bloomburrow Play Booster Box | sealed | AUD:190.00 | 2026-09-30 | notes="pre-order, not shipped yet"

The named fields below (price, date, sold, sold_as and the rest) work exactly the same on sealed lines as they do on card lines: see the named fields reference below.

Sealed Condition Values

sealeddamaged_packaging

Mixing Cards and Sealed Products

A single file can set both defaults at once, @condition and @sealed_condition are order-independent, so declare them up top and switch kinds with @kind as you go. Either can still be overridden per line.

@tcg mtg
@condition near_mint
@sealed_condition damaged_packaging

2 Lightning Bolt | lea | 161 | | | | | AUD:5.00 | 2026-01-02
@kind sealed
1 sealed:Bloomburrow Collector Booster Box

The card line gets near_mint, the sealed line gets damaged_packaging.

Sealed products from several games

The game picked on the import page governs cards. A sealed line can declare a different game for itself with the game named field, so one file can carry sealed products from several TCGs even though every card in it stays one game. The game picked on the import page applies only to lines without game=.

@kind sealed
2 Bloomburrow Collector Booster Box | sealed | AUD:280.00 | 2026-08-01 | game=mtg
1 Base Set Booster Box | sealed | AUD:450.00 | 2026-08-01 | game=pokemon

Building this from a spreadsheet? A formula can generate the game= line for you from separate columns (Qty, Name, Condition, Currency, Price, Date, Game), for Google Sheets or Excel:

=A2&" sealed:"&B2&" | "&C2&" | "&D2&":"&TEXT(E2,"0.00")&" | "&TEXT(F2,"yyyy-mm-dd")&" | game="&G2

Paste the result into the GXF importer. A game can be written either as the code above (mtg, pokemon, and so on) or by its full name, so "Magic: The Gathering" works just as well as mtg.

GXF: named fields reference

Named fields are key=value pipe segments that follow the positional fields on a card or sealed line. Positionals must come first, a positional field after a named field is an error. Quote a value that contains a comma or spaces: notes="pre-order, not shipped yet".

KeyWhat it setsLine kindsExample value
conditioncondition, from the line's own kind of vocabulary (a card line never accepts a sealed value, or vice versa)card and sealedcard: near_mint; sealed: sealed or damaged_packaging
pricewhat you paidcard and sealedAUD:280.00, $280.00, 280.00
datewhen you paid for it. Never a future date, on either kind: a pre-order is recognised from the product's release date, not from thiscard and sealed2026-08-01
tagsyour tagscard and sealedinvestment,boxes
notesfree notecard and sealed"bought at the prerelease"
intentwhy you bought itcard and sealedpersonal, investment or resale
feesdelivery and other costs on the purchasecard and sealedAUD:12.50
groupgroups units bought togethercard and sealedaugust-order
soldwhat you sold it forcard and sealedAUD:340.00
sold_datewhen you sold itcard and sealed2026-09-14
sold_ashow it left your collectioncard and sealedmanual, trade, gift, loss or opened
sold_feescosts on the salecard and sealedAUD:9.95
fromwhat or who it came from: a shop, a marketplace, the player you traded with, the event you won it atcard and sealed"your local game shop"
got_ashow it came into your collection. Leave it out and it counts as boughtcard and sealedpurchase, trade, gift, pull or prize
setset codecard onlyblb
numbercollector numbercard only142
finishingfinishcard onlyfoil
gamesealed lines only; overrides the game picked on the import pagesealed onlymtg, pokemon, onepiece, riftbound, fab, sorcery, lorcana, gundam
treatmenttreatmentcard onlyborderless

Rules to know

  • sold_as=marketplace is not accepted. A completed Gradely marketplace sale is real, immutable history, and an import must never be able to forge one. Sales made on Gradely already appear in your collection automatically.
  • sold_as=manual and sold_as=trade require a sold price. A sale without a price is not a sale.
  • sold_as=gift, loss and opened must not carry a sold price, they are zero-proceeds by definition.
  • sold_as=opened is sealed only. Opening a booster box is a sealed disposal.
  • Opening a product removes its cost from your records until the cards inside are recorded against it. The opened unit stops showing a profit or loss, and the cards you record afterwards carry whatever price you put on them, so until you record them that cost is not counted anywhere.
  • Any sold price requires a sold_date.
  • sold_date cannot be in the future, and cannot be before the purchase date.
  • condition=opened is rejected. It is not a condition you buy something in, use sold_as=opened to record that you opened it.
  • Only got_as=purchase, or leaving got_as out, counts towards the total spend Gradely shows you, because nothing else put cash in. Cost basis is a separate number and Gradely does not change it: whatever price you record against a card stays its cost, whichever way it came in.
  • graded, grade, cert and deck are reserved keys and are rejected with a "not supported on import" message.

Gradely records what you tell it and does the arithmetic on it. It is not an accountant and does not give financial advice. What any of these numbers mean for your own circumstances is between you and your adviser.

Pre-orders

A pre-order needs no special syntax, and no special date. Use the date you actually paid, which is what date always means: a future date is rejected on cards and sealed products alike. What makes a unit a pre-order is that the product has not been released yet, so the badge appears on its own and disappears on release day without you touching anything. The unit counts towards your holdings and cost basis from the day you paid, which is the day the money actually left.