
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A comprehensive TypeScript client for the YGOPRODeck API, providing type-safe access to the Yu-Gi-Oh! card database. See the API guide for more information.
KVStore interface.npm install ygoapi
import { YgoApi } from 'ygoapi'
const api = new YgoApi()
// Get a specific card by name
const darkMagician = await api.getCardByName('Dark Magician')
console.log(darkMagician)
// Search cards by fuzzy name matching
const magicians = await api.searchCards('Magician', {
num: 10,
offset: 0,
})
console.log(magicians.data)
// Get cards from a specific archetype
const blueEyesCards = await api.getCardsByArchetype('Blue-Eyes', {
num: 10,
offset: 0,
})
console.log(blueEyesCards.data)
Run the example:
node examples/basic.js
The YgoApi client supports caching via the KVStore interface. You can provide your own cache implementation to reduce API calls and improve performance.
import { YgoApi } from 'ygoapi';
// Simple in-memory cache implementation
class MemoryCache {
private cache = new Map<string, { value: string; expires: number }>();
get(key: string): string | null {
const item = this.cache.get(key);
if (!item || Date.now() > item.expires) {
this.cache.delete(key);
return null;
}
return item.value;
}
set(key: string, value: string, ttl?: number): void {
const expires = Date.now() + (ttl || 300000); // Default 5 minutes
this.cache.set(key, { value, expires });
}
delete(key: string): void {
this.cache.delete(key);
}
}
// Create API instance with in-memory caching
const api = new YgoApi({
cache: new MemoryCache(),
cacheTtl: 600000 // 10 minutes
});
You can implement the KVStore interface for any storage backend:
import type { KVStore } from 'ygoapi';
// Redis cache example
class RedisCache implements KVStore {
constructor(private redis: RedisClient) {}
async get(key: string): Promise<string | null> {
return this.redis.get(key);
}
async set(key: string, value: string, ttl?: number): Promise<void> {
if (ttl) {
await this.redis.setex(key, Math.floor(ttl / 1000), value);
} else {
await this.redis.set(key, value);
}
}
async delete(key: string): Promise<void> {
await this.redis.del(key);
}
}
const api = new YgoApi({
cache: new RedisCache(redisClient),
cacheTtl: 600000
});
You can also provide a custom KVStore for image caching:
const api = new YgoApi({
imageCache: new MyImageCache()
});
// Get local path to cached image (if your cache returns paths)
const imagePath = await api.getLocalImagePath(card, 'small');
The cache automatically stores successful API responses and serves them for subsequent identical requests until the TTL expires.
You can also use the default export for convenience:
import api from 'ygoapi';
const card = await api.getCardByName('Blue-Eyes White Dragon');
getCardInfo(params?: CardInfoParams): Promise<CardInfoResponse>Get card information with optional filtering parameters.
// Get all cards
const allCards = await api.getCardInfo();
// Get cards with specific filters
const waterDragons = await api.getCardInfo({
attribute: 'WATER',
race: 'Dragon',
type: 'Effect Monster'
});
// Get cards with ATK greater than 2500
const strongCards = await api.getCardInfo({
atk: 'gt2500'
});
getCardByName(name: string): Promise<Card | null>Get a single card by exact name match.
const card = await api.getCardByName('Dark Magician');
if (card) {
console.log(`ATK: ${card.atk}, DEF: ${card.def}`);
}
getCardById(id: string | number): Promise<Card | null>Get a single card by its ID (passcode).
const card = await api.getCardById('46986414'); // Dark Magician
searchCards(fname: string, params?: Omit<CardInfoParams, 'fname'>): Promise<CardInfoResponse>Search cards using fuzzy name matching.
// Find all cards with "Dragon" in the name
const dragons = await api.searchCards('Dragon');
// Find all LIGHT Dragons with "Dragon" in name
const lightDragons = await api.searchCards('Dragon', {
attribute: 'LIGHT'
});
getCardsByArchetype(archetype: string, params?: Omit<CardInfoParams, 'archetype'>): Promise<CardInfoResponse>Get all cards from a specific archetype.
const heroCards = await api.getCardsByArchetype('Elemental HERO');
getCardsBySet(cardset: string, params?: Omit<CardInfoParams, 'cardset'>): Promise<CardInfoResponse>Get all cards from a specific set.
const metalRaiders = await api.getCardsBySet('Metal Raiders');
getRandomCard(): Promise<Card>Get a random card from the database.
const randomCard = await api.getRandomCard();
console.log(`Random card: ${randomCard.name}`);
getAllCardSets(): Promise<CardSetInfo[]>Get information about all card sets.
const sets = await api.getAllCardSets();
sets.forEach(set => {
console.log(`${set.set_name} (${set.set_code}) - ${set.num_of_cards} cards`);
});
getCardSetInfo(setcode: string): Promise<CardSetDetails>Get detailed information about a specific card set.
const setInfo = await api.getCardSetInfo('LOB-001');
getAllArchetypes(): Promise<Archetype[]>Get all available archetypes.
const archetypes = await api.getAllArchetypes();
archetypes.forEach(archetype => {
console.log(archetype.archetype_name);
});
checkDatabaseVersion(): Promise<DatabaseVersion>Check the current database version.
const version = await api.checkDatabaseVersion();
console.log(`Database version: ${version.database_version}`);
console.log(`Last update: ${version.last_update}`);
getStapleCards(params?: Omit<CardInfoParams, 'staple'>): Promise<CardInfoResponse>Get cards considered staples in the game.
const staples = await api.getStapleCards();
getCardsByFormat(format: Format, params?: Omit<CardInfoParams, 'format'>): Promise<CardInfoResponse>Get cards available in a specific format.
const tcgCards = await api.getCardsByFormat('tcg');
const speedDuelCards = await api.getCardsByFormat('speed duel');
const rushDuelCards = await api.getCardsByFormat('rush duel');
const masterDuelCards = await api.getCardsByFormat('master duel');
const genesysCards = await api.getCardsByFormat('genesys');
getCardsByGenesysFormat(params?: Omit<CardInfoParams, 'format' | 'misc'>): Promise<CardInfoResponse>Get cards in the Genesys format with their point values. This method automatically includes misc: 'yes' to ensure genesys_points is returned.
const genesysCards = await api.getCardsByGenesysFormat();
// Access genesys points from misc_info
genesysCards.data.forEach(card => {
const points = card.misc_info?.[0]?.genesys_points ?? 0;
console.log(`${card.name}: ${points} points`);
});
// Filter by archetype while getting genesys points
const blueEyesGenesys = await api.getCardsByGenesysFormat({
archetype: 'Blue-Eyes'
});
getBanlistCards(banlist: BanlistType, params?: Omit<CardInfoParams, 'banlist'>): Promise<CardInfoResponse>Get cards that appear on a specific banlist.
const tcgBanned = await api.getBanlistCards('TCG');
const ocgBanned = await api.getBanlistCards('OCG');
const goatBanned = await api.getBanlistCards('Goat');
getCardsWithPagination(num: number, offset: number, params?: Omit<CardInfoParams, 'num' | 'offset'>): Promise<CardInfoResponse>Get cards with pagination support.
const firstPage = await api.getCardsWithPagination(50, 0);
console.log(`Total cards: ${firstPage.meta?.total_rows}`);
console.log(`Pages remaining: ${firstPage.meta?.pages_remaining}`);
// Get cards by type
const spellCards = await api.getCardsByType('Spell Card');
const linkMonsters = await api.getCardsByType('Link Monster');
// Get cards by attribute
const fireCards = await api.getCardsByAttribute('FIRE');
const lightCards = await api.getCardsByAttribute('LIGHT');
// Get cards by race
const dragons = await api.getCardsByRace('Dragon');
const spellcasters = await api.getCardsByRace('Spellcaster');
// Get cards by level
const level4Cards = await api.getCardsByLevel(4);
const highLevelCards = await api.getCardsByLevel('gte8');
// Get cards by ATK/DEF
const strongCards = await api.getCardsByATK('gte3000');
const defensiveCards = await api.getCardsByDEF('gte2500');
// Get cards with misc info (views, formats, dates, etc.)
const cardsWithMisc = await api.getCardsWithMiscInfo({
archetype: 'Blue-Eyes'
});
buildComparison(operator: ComparisonOperator, value: number)Build comparison queries for ATK, DEF, or Level.
import { buildComparison } from 'ygoapi';
const strongCards = await api.getCardInfo({
atk: buildComparison('gte', 3000) // ATK >= 3000
});
getCardImages(card: Card)Extract image URLs from a card object.
import { getCardImages } from 'ygoapi';
const card = await api.getCardByName('Dark Magician');
if (card) {
const images = getCardImages(card);
console.log('Default image:', images.default.image_url);
console.log('Alternative images:', images.alternates);
}
import { isMonsterCard, isSpellCard, isTrapCard, isExtraDeckMonster } from 'ygoapi';
const card = await api.getCardByName('Blue-Eyes White Dragon');
if (card) {
console.log('Is monster:', isMonsterCard(card));
console.log('Is spell:', isSpellCard(card));
console.log('Is trap:', isTrapCard(card));
console.log('Is extra deck:', isExtraDeckMonster(card));
}
Search for Link monsters with specific criteria:
// Get all Link monsters
const linkMonsters = await api.getCardInfo({
type: 'Link Monster'
});
// Get Link-2 monsters
const link2Monsters = await api.getCardInfo({
type: 'Link Monster',
link: 2
});
// Get Link monsters with specific markers
const topBottomLinks = await api.getCardInfo({
type: 'Link Monster',
linkmarker: ['Top', 'Bottom']
});
Search for Pendulum monsters by scale:
// Get all Pendulum monsters
const pendulums = await api.getCardInfo({
type: 'Pendulum Effect Monster'
});
// Get Pendulum monsters with scale 7
const scale7Pendulums = await api.getCardInfo({
type: 'Pendulum Effect Monster',
scale: 7
});
// Cards with effects vs without effects
const effectCards = await api.getCardInfo({
has_effect: true,
type: 'Effect Monster'
});
const vanillaCards = await api.getCardInfo({
has_effect: false
});
// Date-based filtering
const oldCards = await api.getCardInfo({
startdate: '2000-01-01',
enddate: '2005-12-31',
dateregion: 'tcg'
});
// Multiple card names/IDs
const specificCards = await api.getCardInfo({
name: 'Dark Magician|Blue-Eyes White Dragon'
});
const cardsByIds = await api.getCardInfo({
id: '46986414,89631139'
});
The CardInfoParams interface supports extensive filtering options:
interface CardInfoParams {
// Card identification
name?: string; // Exact name match
fname?: string; // Fuzzy name search
id?: string | number; // Card ID/passcode
konami_id?: string | number; // Konami ID
// Card properties
type?: CardType; // Card type
atk?: number | `${ComparisonOperator}${number}`;
def?: number | `${ComparisonOperator}${number}`;
level?: number | `${ComparisonOperator}${number}`;
race?: CardRace | CardRace[]; // Card race/type
attribute?: Attribute | Attribute[];
// Link monsters
link?: number; // Link value
linkmarker?: LinkMarker | LinkMarker[];
// Pendulum monsters
scale?: number; // Pendulum scale
// Set/Archetype
cardset?: string; // Card set name
archetype?: string; // Archetype name
// Format/Banlist
banlist?: BanlistType; // TCG, OCG, or Goat
format?: Format; // Game format (tcg, goat, ocg goat, speed duel, master duel, rush duel, duel links, genesys)
// Special filters
staple?: "yes"; // Staple cards only
has_effect?: boolean; // Cards with/without effects
// Date filters
startdate?: string; // YYYY-MM-DD
enddate?: string; // YYYY-MM-DD
dateregion?: DateRegion; // tcg or ocg
// Sorting/Pagination
sort?: SortOption; // Sort order
num?: number; // Number of results
offset?: number; // Result offset
// Additional options
misc?: "yes"; // Include misc info
tcgplayer_data?: boolean; // Use TCGPlayer data
// Language
language?: Language; // fr, de, it, pt
}
For ATK, DEF, and Level fields, you can use comparison operators:
// Examples
atk: 2500, // Exactly 2500
atk: "lt2500", // Less than 2500
atk: "lte2500", // Less than or equal to 2500
atk: "gt2500", // Greater than 2500
atk: "gte2500", // Greater than or equal to 2500
Many parameters accept arrays for multiple values:
const cards = await api.getCardInfo({
attribute: ['LIGHT', 'DARK'], // LIGHT OR DARK
race: ['Dragon', 'Spellcaster'], // Dragon OR Spellcaster
linkmarker: ['Top', 'Bottom'] // Top AND Bottom link markers
});
The API supports multiple languages:
// Get cards in French
const frenchCards = await api.getCardInfo({
fname: 'Magicien',
language: 'fr'
});
// Get German Blue-Eyes archetype
const germanBlueEyes = await api.getCardsByArchetype('Blue-Eyes', {
language: 'de'
});
Supported languages:
fr - Frenchde - Germanit - Italianpt - PortugueseNote: Card images are only available in English.
All card types from the game are supported:
type CardType =
| "Effect Monster"
| "Normal Monster"
| "Fusion Monster"
| "Synchro Monster"
| "XYZ Monster"
| "Link Monster"
| "Spell Card"
| "Trap Card"
// ... and many more
type Attribute =
| "DARK"
| "LIGHT"
| "EARTH"
| "FIRE"
| "WATER"
| "WIND"
| "DIVINE"
Monster races:
type MonsterRace =
| "Dragon"
| "Spellcaster"
| "Warrior"
| "Beast-Warrior"
| "Fiend"
// ... and more
Spell races:
type SpellRace =
| "Normal"
| "Quick-Play"
| "Field"
| "Equip"
| "Continuous"
| "Ritual"
Trap races:
type TrapRace =
| "Normal"
| "Continuous"
| "Counter"
The client includes comprehensive error handling:
import { YgoApiError } from 'ygoapi';
try {
const card = await api.getCardByName('Invalid Card Name');
} catch (error) {
if (error instanceof YgoApiError) {
console.log(`API Error ${error.statusCode}: ${error.message}`);
} else {
console.log('Network or other error:', error);
}
}
The YGOPRODeck API has rate limiting:
The YgoApi client automatically throttles requests to comply with the 20 requests/second limit. It uses a built-in queue system (SignalBasedQueue) that spaces out requests to avoid bans. Throttling behavior can be customized by providing a different interval or your own queue implementation via the requestQueue option and the TimeQueue interface.
The default signal-based queue allows up to 20 requests to start per second, but does not wait for their completion before processing the next requests.
import { YgoApi, SignalBasedQueue } from 'ygoapi'
import type { TimeQueue } from 'ygoapi'
const api = new YgoApi({
requestQueue: new SignalBasedQueue(1000) // 1000ms throttling between fetch starts
})
class MyQueue implements TimeQueue {
// The method needs to pass down the resolution of the task
enqueue<T>(task: () => Promise<T>, signal: AbortSignal): Promise<T> {
//... Your implementation ...
}
// ... Your implementation ...
}
const myApi = new YgoApi({
requestQueue: new MyQueue()
})
This library includes comprehensive test coverage with 53+ tests covering all features:
# Run tests
bun test
# Run tests with coverage
bun test --coverage
Test categories:
num and offset parametersimport { YgoApi, isMonsterCard, isSpellCard, isTrapCard } from 'ygoapi';
const api = new YgoApi();
async function searchCards(query: string) {
try {
const response = await api.searchCards(query, {
sort: 'name',
num: 20
});
return response.data.map(card => ({
id: card.id,
name: card.name,
type: card.type,
atk: card.atk,
def: card.def,
image: card.card_images[0]?.image_url_small
}));
} catch (error) {
console.error('Search failed:', error);
return [];
}
}
import { YgoApi, isMonsterCard, isSpellCard, isTrapCard } from 'ygoapi';
const api = new YgoApi();
async function getArchetypeCards(archetype: string) {
const response = await api.getCardsByArchetype(archetype);
const monsters = response.data.filter(isMonsterCard);
const spells = response.data.filter(isSpellCard);
const traps = response.data.filter(isTrapCard);
return { monsters, spells, traps };
}
import { YgoApi } from 'ygoapi';
const api = new YgoApi();
async function getCardPrices(cardName: string) {
const card = await api.getCardByName(cardName);
if (!card) return null;
const prices = card.card_prices[0];
return {
tcgplayer: parseFloat(prices.tcgplayer_price),
cardmarket: parseFloat(prices.cardmarket_price),
ebay: parseFloat(prices.ebay_price),
amazon: parseFloat(prices.amazon_price),
coolstuffinc: parseFloat(prices.coolstuffinc_price)
};
}
Please see CONTRIBUTING.md for contribution guidelines.
This project is licensed under the MIT License.
This library provides 100% coverage of the YGOPRODeck API:
/cardinfo.php)/randomcard.php)/cardsets.php)/cardsetsinfo.php)/archetypes.php)/checkDBVer.php)name, fname, id, konami_idtype, atk, def, level, race, attributelink, linkmarkerscalecardset, archetype, banlist, format, staple, has_effectstartdate, enddate, dateregionsort, num, offsetmisc, tcgplayer_data, languagelt, lte, gt, gte)⚠️ Images: Do not continually hotlink images directly from this site. Please download and re-host the images yourself. Failure to do so will result in an IP blacklist. Please read the guide on where to download images.
💾 Data Caching: Please download and store all data pulled from this API locally to keep the amount of API calls used to a minimum. Failure to do so may result in either your IP address being blacklisted or the API being rolled back.
⏱️ Rate Limiting: Rate limiting is enabled on the API. The rate limit is 20 requests per 1 second. If you exceed this, you are blocked from accessing the API for 1 hour.
This library is not affiliated with YGOPRODeck, Konami, or Yu-Gi-Oh!. Yu-Gi-Oh! is a trademark of Konami Digital Entertainment, Inc.
FAQs
TypeScript client for the YGOPRODeck API v7 - Yu-Gi-Oh! card database access
We found that ygoapi demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.