TypeScript/JavaScript client for the Pkmn Prices API. Pokemon TCG card pricing from TCGPlayer, Cardmarket, and eBay.
No dependencies. Uses the built-in fetch, so it runs on Node 18+, browsers, Deno, Bun, and Workers. Ships ESM and CommonJS with types.
npm install @pkmnprices/sdkimport { PkmnPrices } from "@pkmnprices/sdk";
const client = new PkmnPrices({ apiKey: "pk_your_key_here" });
const { data } = await client.cards.list({ name: "charizard", per_page: 10 });
const card = await client.cards.get(data[0].id);
for (const price of card.prices) {
const symbol = price.currency === "EUR" ? "€" : "$";
console.log(`${price.source}: ${symbol}${price.market_price}`);
}Grab an API key from https://pkmnprices.com/dashboard.
new PkmnPrices({
apiKey: "pk_...", // sent as the x-api-key header
maxRetries: 2, // retries on 429 rate limits and 5xx/network errors
timeoutMs: 30_000, // per-request timeout
});Rate-limit 429s are retried with backoff. Credit-limit 429s (credit_limit_exceeded) are not, since they don't reset until the next day.
List endpoints return { data, pagination }. Listing endpoints (eBay/Cardmarket) use cursors instead. Both have iterator helpers if you'd rather not track pages or cursors yourself:
for await (const card of client.cards.iterate({ name: "charizard" })) {
console.log(card.name);
}
const allSets = await client.sets.listAll({ language: "english" });
for await (const sale of client.cards.listings.iterateEbay(789, { grader: "PSA", grade: "10" })) {
console.log(sale.title, sale.price);
}Every price has a currency field. Pass currency ("usd" or "eur") to filter, or leave it off to get everything your plan allows. EUR (Cardmarket) prices need a Pro plan; a free key asking for eur gets a ForbiddenError.
const card = await client.cards.get(789, { currency: "usd" });client.health()
client.sets list get iterate listAll
client.cards list get iterate listAll priceHistory iteratePriceHistory
client.cards.listings ebay iterateEbay allEbay cardmarket iterateCardmarket allCardmarket
client.sealed list get iterate listAll priceHistory listings iterateListings allListings
Everything thrown extends PkmnPricesError, which carries status, code, message, rateLimit, and retryAfterMs.
import { ForbiddenError, NotFoundError, RateLimitError } from "@pkmnprices/sdk";
try {
await client.cards.get(789, { currency: "eur" });
} catch (err) {
if (err instanceof ForbiddenError) {
// needs a higher plan
} else if (err instanceof NotFoundError) {
// no such card
} else if (err instanceof RateLimitError) {
// ran out of retries
}
}Subclasses: BadRequestError (400), UnauthorizedError (401), ForbiddenError (403), NotFoundError (404), ConflictError (409), CreditLimitError and RateLimitError (429), InternalServerError (5xx), ConnectionError (network/timeout).
MIT