Cross-Platform Gap — TCG Arbitrage Detection Methodology
How GapSense detects cross-platform TCG arbitrage across nine marketplaces — card identity, grade purity, variant matching, and confidence tiering. The four checks every published gap must pass.
What a cross-platform gap is
A cross-platform gap is a price difference for the same card at the same grade and variant across two different marketplaces, large enough to be tradeable after fees. It is not a price comparison — comparison sites publish prices side by side and let the reader figure out whether the spread is real. A gap engine commits to four claims:
- The cards on both sides are the same physical product.
- The grade band is identical (PSA 10 only matches PSA 10).
- The variant is identical (alt-art, full-art, promo, language, region).
- The spread is large enough to survive both platforms' fees + redemption + FX.
If any of those four fail, GapSense does not publish the gap.
Card identity match
Identity is reduced to a deterministic card_key built from set_code, set_number, variant, grade, and language:
card_key = "{set_code}::{set_number}::{variant}::{grade}::{language}"
Example: obf::223::normal::psa-9::en is Charizard ex from Obsidian Flames #223, normal print, PSA 9, English. A listing only joins a gap if its card_key matches exactly. Two complications force more than just string equality:
- Crypto-native platforms (Courtyard, Phygital, CollectorCrypt, Renaiss, Beezie) often title cards by region or NFT collection, not by canonical EN set number. GapSense uses Jaccard similarity ≥ 0.5 on the parsed name as a secondary guard, with set_code falling back to
UNKNOWNwhen the title is unparseable. - Region collisions like Courtyard's "308 JP" promo number conflicting with a different EN release. Resolved by language gate:
languagemust match exactly.
Grade and variant purity
Grading bands are absolute walls. The matching engine refuses to compare:
| Left side | Right side | Status |
|---|---|---|
| PSA 10 | PSA 9 | Rejected |
| PSA 10 | BGS 10 | Rejected (different grader) |
| PSA 10 | CGC 10 | Rejected |
| raw NM | raw LP | Rejected |
| raw NM | PSA 10 | Rejected (raw vs graded) |
| PSA 10 alt-art | PSA 10 normal | Rejected (variant mismatch) |
| PSA 10 EN | PSA 10 JP | Rejected (language mismatch) |
This is the single most consequential design decision in the engine. A naive aggregator that averages across grades publishes inflated arbitrage that vanishes on attempted execution.
Match confidence tiers
Even with strict identity, real-world data has noise. GapSense classifies each gap into one of three tiers, returned in the API as match_tier:
- primary_exact — full
card_keymatch across both platforms. Safe for autonomous execution. - variant_match — identity match with one variant ambiguity (e.g. promo number resolved by name match). Returned with
confidence: MEDIUM. - loose_name — name + set_code only, used when one platform reports
set_number=UNKNOWN. Returned withconfidence: LOW; agents instructed not to act without independent verification.
The hard constraint published to all agents: never act on confidence=LOW gaps without independent verification.
The nine platforms
| Platform | Currency | Settlement | Notes |
|---|---|---|---|
| eBay | USD | Direct shipping | Largest sample size, most reliable tape |
| TCGPlayer | USD | Direct shipping | API-backed, raw and graded |
| CardMarket | EUR | Direct shipping | Europe primary, FX gate active |
| Courtyard | USD | NFT redeemable | Algolia-indexed, redemption cost modeled |
| Phygital | USDC | NFT redeemable | 5,971+ Pokemon listings, native API |
| CollectorCrypt | SOL | NFT redeemable | Magic Eden activities |
| Renaiss | USDT | NFT redeemable | tRPC API, 3,998+ listings |
| SNKRDUNK | JPY | JP escrow | PSA + raw, JP cards underpriced internationally |
| Beezie | USDC | Vault-held | Adjusted EV signal source |
Three of the nine (Phygital, Renaiss, Beezie) are pay-with-stablecoin platforms — the precondition for the agent-native pricing model documented in the agent guide.
Related concepts
FAQ
Why not just compare prices across sites?
Because most published spreads vanish on execution. A side-by-side price table that mixes raw with graded, or PSA 10 with CGC 10, advertises an arbitrage that does not exist. A gap engine commits to identity, grade, variant, and post-fee profitability before publishing.
What is a card_key?
A card_key is the deterministic identity string GapSense uses to join listings across platforms. Format: set_code::set_number::variant::grade::language. Example: obf::223::normal::psa-9::en is Charizard ex from Obsidian Flames #223, normal print, PSA 9, English.
Why does GapSense reject PSA 10 vs CGC 10 comparisons?
Different graders sustain different multiples for the same card. The PSA premium is real and persistent. Treating PSA 10 and CGC 10 as substitutable invents arbitrage that the market does not pay out.
How are crypto-native NFT card titles matched?
When a platform reports set_number=UNKNOWN or uses a region-specific number that does not match the EN canonical, GapSense falls back to Jaccard similarity ≥ 0.5 on the parsed card name plus a language gate. The result is returned as match_tier=loose_name with confidence=LOW.