Discord Bot Integration
Create a Discord bot that responds to commands like /card Charizard with card info and current prices.
What You’ll Build
Section titled “What You’ll Build”- Discord slash command for card lookup
- Search across all 5 TCGs
- Display prices and card images
- Handle multiple search results
Prerequisites
Section titled “Prerequisites”- Node.js 18+
- Pulls API key
- Discord bot token (create at discord.com/developers)
-
Create project
Terminal window mkdir pulls-discord-bot && cd pulls-discord-botnpm init -ynpm install @pulls/sdk discord.js dotenv -
Configure environment
.env PULLS_API_KEY=pk_live_...DISCORD_TOKEN=...DISCORD_CLIENT_ID=... -
Register slash command
src/register.ts import { REST, Routes, SlashCommandBuilder } from 'discord.js'import 'dotenv/config'const command = new SlashCommandBuilder().setName('card').setDescription('Look up a TCG card').addStringOption(opt =>opt.setName('name').setDescription('Card name to search').setRequired(true)).addStringOption(opt =>opt.setName('tcg').setDescription('Filter by TCG').addChoices({ name: 'Pokemon', value: 'pokemon' },{ name: 'Magic', value: 'mtg' },{ name: 'Yu-Gi-Oh!', value: 'yugioh' },{ name: 'Lorcana', value: 'lorcana' },{ name: 'One Piece', value: 'onepiece' },))const rest = new REST().setToken(process.env.DISCORD_TOKEN!)await rest.put(Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!),{ body: [command.toJSON()] })console.log('Registered /card command')
Bot Implementation
Section titled “Bot Implementation”import { Client, GatewayIntentBits, EmbedBuilder } from 'discord.js'import { PullsAPI } from '@pulls/sdk'import 'dotenv/config'
const pulls = new PullsAPI({ apiKey: process.env.PULLS_API_KEY! })const client = new Client({ intents: [GatewayIntentBits.Guilds] })
client.on('interactionCreate', async (interaction) => { if (!interaction.isChatInputCommand()) return if (interaction.commandName !== 'card') return
await interaction.deferReply()
const name = interaction.options.getString('name', true) const tcg = interaction.options.getString('tcg')
try { const results = await pulls.search.cards({ query: name, tcg: tcg ?? undefined, limit: 5 })
if (results.length === 0) { await interaction.editReply(`No cards found for "${name}"`) return }
const card = results[0] const embed = buildCardEmbed(card) await interaction.editReply({ embeds: [embed] })
} catch (error) { console.error(error) await interaction.editReply('Error fetching card data') }})
function buildCardEmbed(card: Card): EmbedBuilder { const tcgColors: Record<string, number> = { pokemon: 0xFFCB05, mtg: 0x000000, yugioh: 0x8B4513, lorcana: 0x4B0082, onepiece: 0xDC143C, }
return new EmbedBuilder() .setTitle(card.name) .setURL(`https://pulls.app/cards/${card.id}`) .setColor(tcgColors[card.tcg] ?? 0x3b82f6) .setThumbnail(card.imageUrl) .addFields( { name: 'Set', value: card.set.name, inline: true }, { name: 'TCG', value: card.tcg.toUpperCase(), inline: true }, { name: 'Number', value: card.number ?? 'N/A', inline: true }, { name: 'Market Price', value: `$${card.prices?.market?.toFixed(2) ?? 'N/A'}`, inline: true }, { name: 'Low', value: `$${card.prices?.low?.toFixed(2) ?? 'N/A'}`, inline: true }, { name: 'High', value: `$${card.prices?.high?.toFixed(2) ?? 'N/A'}`, inline: true }, ) .setFooter({ text: 'Powered by Pulls API' })}
client.login(process.env.DISCORD_TOKEN!)Running the Bot
Section titled “Running the Bot”# First, register the commandnpx ts-node src/register.ts
# Then start the botnpx ts-node src/bot.tsExample Output
Section titled “Example Output”When a user runs /card Charizard tcg:pokemon:
┌─────────────────────────────────────┐│ Charizard ││ https://pulls.app/cards/base1-4 │├─────────────────────────────────────┤│ Set: Base Set │ TCG: POKEMON ││ Number: 4/102 │ │├─────────────────────────────────────┤│ Market: $420.00 │ Low: $350.00 ││ High: $550.00 │ │├─────────────────────────────────────┤│ Powered by Pulls API │└─────────────────────────────────────┘Enhancements
Section titled “Enhancements”- Add autocomplete for card names
- Support graded price lookup (
/graded PSA 10 Charizard) - Add price alerts (
/watch sv7-001) - Include price history charts as images