back to blog
Dynamic Pricing for TCG: The Math Behind SantahsCards Bulk Quotes

Dynamic Pricing for TCG: The Math Behind SantahsCards Bulk Quotes

January 18, 2026

Dynamic Pricing for TCG

A wholesale TCG operation lives or dies by its pricing. Too high and you lose customers to competitors who have access to the same distributors. Too low and you're subsidizing your buyers' businesses. Dynamic, market-driven pricing — anchored to a real-time TCGPlayer market signal — is the only way to consistently land in the right zone.

This is how the SantahsCards pricing engine works under the hood.

The market signal

TCGPlayer publishes a "market price" for every product, derived from recent sales. It's not perfect — it lags by a few hours and can be skewed by single large transactions — but it's the closest thing to a canonical price that exists in the U.S. TCG market.

Every SKU in the inventory database has a TCG_PLAYER_LINK field. When the storefront API loads, it extracts the product ID from each link and asks for the current market price via two endpoints:

  1. mpapi.tcgplayer.com/v2/product/<id>/details — the lightweight endpoint that returns market + low + mid pricing
  2. The product page HTML's __NEXT_DATA__ blob — fallback when the JSON endpoint is throttled or returns nothing

The result gets cached for 60 seconds and used as the input to every downstream pricing calculation.

The bulk-pricing formula

unitPrice = marketPrice × (bulkPercentage / 100)
lineTotal = unitPrice × quantity

bulkPercentage is per-SKU and lives in Airtable. It's the lever I tune by hand based on competitive intel, holding cost, and how aggressively I want to move a given SKU. A typical range:

  • Hot SKUs (recent releases, high turnover): 90–95% of market
  • Slower-moving sealed: 75–85% of market
  • Premium or scarce items: 95–100% of market, sometimes a small premium

For volume orders, customers get an additional discount on top — usually 1–3% per "tier" up. The tiers (50–100, 100–250, 250–1,000, 1,000+) are exposed in the wholesale preorder funnel on cravinos.dev.

Why scrape rather than use the official API

TCGPlayer has an API. It's gated by their partner program, which is selective about who gets in. Scraping the public market price is functionally identical for our use case and dramatically more flexible:

  • No partner-program gate. I can iterate on pricing logic without waiting for approval.
  • Rate-limit elasticity. Through residential proxies (covered in another post), I can scale fetches without negotiating quota.
  • Data shape control. The scraped response gives me exactly what I need; the API gives me what they want me to have.

The trade-off is that I have to handle TCGPlayer's anti-bot measures, which is what the evomi-proxy-tool stack is for.

Edge cases

Most of the engineering effort goes into cases where the market price isn't clean:

  • Out-of-stock or OOP SKUs with no recent sales: the market price endpoint returns null, so I fall back to a per-SKU floor price stored in Airtable.
  • Newly listed SKUs with no sales yet: same fallback, plus a "preview" flag to skip the SKU in automated quotes.
  • Promotional bundles that don't have a single TCGPlayer product: I unbundle to component SKUs and price them independently.
  • Coming-soon items (the wholesale preorder catalog): use a stored quote-floor price and clearly mark the quote as preliminary.

What I'm working on next

The current engine treats every SKU as independent. The next iteration will look at cross-product signals — when the market price for sealed Booster Box X moves, what's the historical correlation with Bundle X and ETB X? Knowing that, I can preempt re-pricing rather than waiting for the market to update each individual SKU.

The honest version: this is a small operation and 80% of the value comes from the simple formula above. The cross-product modeling is a fun problem and a marginal improvement at best. But it'll be a fun post when I ship it.