Building a Price Tracker
Build a price tracker that monitors card prices across multiple TCGs. By the end, you’ll have a working application that tracks prices and alerts you to changes.
What You’ll Build
Section titled “What You’ll Build”- Fetch current prices for any card
- Store historical price data
- Detect significant price changes
- Send alerts via Discord webhook
Prerequisites
Section titled “Prerequisites”- Node.js 18+
- Pulls API key (Free tier works)
- Discord webhook URL (optional, for alerts)
-
Create project and install dependencies
Terminal window mkdir price-tracker && cd price-trackernpm init -ynpm install @pulls/sdk dotenv -
Configure environment
.env PULLS_API_KEY=pk_live_your_key_hereDISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... -
Initialize the SDK
src/index.ts import { PullsAPI } from '@pulls/sdk'import 'dotenv/config'const pulls = new PullsAPI({apiKey: process.env.PULLS_API_KEY!})
Fetching Prices
Section titled “Fetching Prices”Get current market prices for a card:
async function getCardPrice(cardId: string) { const card = await pulls.cards.get(cardId, { includePrices: true })
return { id: card.id, name: card.name, tcg: card.tcg, prices: card.prices }}
// Usageconst charizard = await getCardPrice('base1-4')console.log(`${charizard.name}: $${charizard.prices.market}`)// Output: Charizard: $420.00Tracking Multiple Cards
Section titled “Tracking Multiple Cards”Create a watchlist and fetch prices in bulk:
const watchlist = [ 'sv7-001', // Pokemon 'ltr-1', // Lorcana 'neo-1', // One Piece]
async function checkWatchlist() { const prices = await pulls.prices.list({ cardIds: watchlist })
return prices.map(p => ({ cardId: p.cardId, market: p.market, change24h: p.change24h }))}Detecting Price Changes
Section titled “Detecting Price Changes”Compare current prices against stored values:
interface PriceRecord { cardId: string price: number timestamp: Date}
const priceHistory: Map<string, PriceRecord[]> = new Map()
function detectSignificantChange( cardId: string, currentPrice: number, thresholdPercent: number = 10): boolean { const history = priceHistory.get(cardId) ?? [] if (history.length === 0) return false
const previousPrice = history[history.length - 1].price const changePercent = ((currentPrice - previousPrice) / previousPrice) * 100
return Math.abs(changePercent) >= thresholdPercent}
function recordPrice(cardId: string, price: number) { const history = priceHistory.get(cardId) ?? [] history.push({ cardId, price, timestamp: new Date() }) priceHistory.set(cardId, history)}Sending Discord Alerts
Section titled “Sending Discord Alerts”Notify when prices change significantly:
async function sendDiscordAlert( cardName: string, oldPrice: number, newPrice: number) { const change = ((newPrice - oldPrice) / oldPrice) * 100 const direction = change > 0 ? '📈' : '📉'
await fetch(process.env.DISCORD_WEBHOOK_URL!, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ embeds: [{ title: `${direction} Price Alert: ${cardName}`, description: `Price changed ${change.toFixed(1)}%`, fields: [ { name: 'Old Price', value: `$${oldPrice.toFixed(2)}`, inline: true }, { name: 'New Price', value: `$${newPrice.toFixed(2)}`, inline: true }, ], color: change > 0 ? 0x22c55e : 0xef4444 }] }) })}Complete Example
Section titled “Complete Example”Tie it all together with a scheduled check:
import { PullsAPI } from '@pulls/sdk'import 'dotenv/config'
const pulls = new PullsAPI({ apiKey: process.env.PULLS_API_KEY! })
const watchlist = ['sv7-001', 'base1-4', 'ltr-1']const priceHistory: Map<string, number> = new Map()
async function checkPrices() { console.log(`[${new Date().toISOString()}] Checking prices...`)
const prices = await pulls.prices.list({ cardIds: watchlist })
for (const price of prices) { const previousPrice = priceHistory.get(price.cardId) priceHistory.set(price.cardId, price.market)
if (previousPrice) { const change = ((price.market - previousPrice) / previousPrice) * 100 if (Math.abs(change) >= 10) { console.log(`ALERT: ${price.cardId} changed ${change.toFixed(1)}%`) // await sendDiscordAlert(...) } } }}
// Check every 15 minutessetInterval(checkPrices, 15 * 60 * 1000)checkPrices() // Initial checkNext Steps
Section titled “Next Steps”- Add persistent storage (SQLite, Redis)
- Track graded card prices with
prices.graded - Use webhooks instead of polling (Pro+ plans)
- Build a web dashboard with Next.js
Related
Section titled “Related”- API Reference: Prices
- Webhooks Guide (coming soon)
- Discord Bot Integration