npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

justtcg-js

v0.2.1

Published

The official JavaScript/TypeScript SDK for the JustTCG API.

Readme

JustTCG JS/TS SDK

NPM Version Build Status License: MIT

The official JavaScript/TypeScript SDK for the JustTCG API. Access real-time and historical pricing data for the world's most popular Trading Card Games.

Features

  • ✅ Modern & Type-Safe: Written entirely in TypeScript for a superior developer experience with static typing and autocomplete.
  • 🔐 Versioned API Access: Clean, explicit access to API versions, starting with v1, ensuring your integrations are stable and future-proof.
  • 🧼 Clean Data Models: Raw API responses are automatically transformed into clean, intuitive JavaScript objects (e.g., prices in dollars, camelCase properties).
  • 🚨 Robust Error Handling: Predictable, typed errors allow you to gracefully handle API issues like invalid keys or rate limits.
  • 🚀 Zero Dependencies: A lightweight package with no production dependencies for fast and secure installation.
  • 🤖 Node.js First: Optimized for server-side environments, with support for environment variable authentication out of the box.

Installation

npm install justtcg-js

Quick Start

Get your API key from your JustTCG Dashboard. For security, we recommend storing your API key in an environment variable named JUSTTCG_API_KEY.

import { JustTCG } from 'justtcg-js';

async function findTopCards() {
  try {
    // The client automatically looks for the JUSTTCG_API_KEY environment variable
    const client = new JustTCG();

    // Or, you can provide options directly in the constructor
    // const client = new JustTCG({ 
    //   apiKey: 'your_api_key_here',
    //   debug: true // Enable request logging
    // });

    console.log(`Searching for the most valuable cards in Disney Lorcana: The First Chapter...`);

    const response = await client.v1.cards.get({
      game: 'Disney Lorcana',
      set: 'the-first-chapter-disney-lorcana',
      orderBy: 'price',
      order: 'desc',
      limit: 10,
    });

    console.log('\n--- Top 10 Most Valuable Cards ---');
    response.data.forEach((card, index) => {
      // Find the most expensive variant for display (e.g., the Foil version)
      const topVariant = card.variants.sort((a, b) => (b.price ?? 0) - (a.price ?? 0))[0];

      const price = topVariant?.price?.toFixed(2) ?? 'N/A';
      const printing = topVariant?.printing ? `(${topVariant.printing})` : '';

      console.log(`${index + 1}. ${card.name} ${printing} - $${price}`);
    });

    console.log(`\nAPI requests remaining today: ${response.usage.apiDailyRequestsRemaining}`);
  } catch (error) {
    console.error('An error occurred:', (error as Error).message);
    process.exit(1);
  }
}

findTopCards();

The Response Object

All successful method calls from the client return a consistent JustTCGApiResponse object. It's crucial to understand its structure.

interface JustTCGApiResponse<T> {
  /** The main data payload from the API. The type of T depends on the method called. */
  data: T;

  /** Pagination metadata, ONLY present on paginated endpoints like `cards.get()` and `sets.list()`. */
  pagination?: {
    total: number;
    limit: number;
    offset: number;
    hasMore: boolean;
  };

  /** API usage metadata, included in every successful response. */
  usage: {
    apiRequestLimit: number;
    apiDailyLimit: number;
    apiRateLimit: number;
    apiRequestsUsed: number;
    apiDailyRequestsUsed: number;
    apiRequestsRemaining: number;
    apiDailyRequestsRemaining: number;
    apiPlan: string;
  };

  /** If the API returns an error (e.g., validation), this field will contain the message. */
  error?: string;

  /** An error code corresponding to the error message. */
  code?: string;
}

API Reference

The client is organized by API version, resource, and method. The structure is always: client.[version].[resource].[method](params).

v1.games

.list()

Fetches a list of all supported Trading Card Games.

  • Parameters: None.

  • Returns: Promise<JustTCGApiResponse<Game[]>>

Response data Object (Game):

{
  id: string; // The unique identifier for the game (e.g., 'pokemon')
  name: string; // The full name of the game (e.g., 'Pokemon')
  cards_count: number; // Total number of cards in the game
  sets_count: number; // Total number of sets in the game
  sealed_count: number; // Number of sealed products in the game
  last_updated: number; // Last updated timestamp (Unix seconds)
  game_value_usd: number; // Total value of the game's cards (USD)
  game_value_change_7d_pct: number; // Percentage change in game value over 7 days
  game_value_change_30d_pct: number; // Percentage change in game value over 30 days
  game_value_change_90d_pct: number; // Percentage change in game value over 90 days
  cards_pos_7d_count: number; // Number of cards with positive price change in 7d
  cards_neg_7d_count: number; // Number of cards with negative price change in 7d
  sealed_cards_pos_7d_count: number; // Number of sealed products with positive price change in 7d
  sealed_cards_neg_7d_count: number; // Number of sealed products with negative price change in 7d
  cards_pos_30d_count: number; // Number of cards with positive price change in 30d
  cards_neg_30d_count: number; // Number of cards with negative price change in 30d
  sealed_cards_pos_30d_count: number; // Number of sealed products with positive price change in 30d
  sealed_cards_neg_30d_count: number; // Number of sealed products with negative price change in 30d
  cards_pos_90d_count: number; // Number of cards with positive price change in 90d
  cards_neg_90d_count: number; // Number of cards with negative price change in 90d
  sealed_cards_pos_90d_count: number; // Number of sealed products with positive price change in 90d
  sealed_cards_neg_90d_count: number; // Number of sealed products with negative price change in 90d
}

v1.sets

.list(params)

Fetches a list of sets, which must be filtered by game.

  • Parameters: | Parameter | Type | Required | Description | | :-------- | :----- | :------- | :-------------------------------------------------------- | | game | string | Yes | The name of the game to filter sets by (e.g., 'Pokemon'). |

  • Returns: Promise<JustTCGApiResponse<Set[]>> (This response includes the pagination object).

Response data Object (Set):

{
  id: string; // The unique identifier for the set
  name: string; // The name of the set (e.g., 'Base Set')
  gameId: string; // The ID of the game this set belongs to
  game: string; // The name of the game this set belongs to
  count: number; // The number of cards in the set
  variants_count: number; // The total number of variants in the set
  sealed_count: number; // The number of sealed products in the set
  release_date: string; // The release date in ISO 8601 format
  set_value_usd: number; // Total value of the set's cards (USD)
  set_value_change_7d_pct: number; // Percentage change in set value over 7 days
  set_value_change_30d_pct: number; // Percentage change in set value over 30 days
  set_value_change_90d_pct: number; // Percentage change in set value over 90 days
}

v1.cards

.get(params)

A powerful and flexible method to browse, filter, and retrieve a paginated list of cards.

| Parameter | Type | Description | | :-------------------- | :------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | tcgplayerId | string | A TCGplayer product ID to look up. | | tcgplayerSkuId | string | The TCGplayer SKU ID for a specific variant. | | cardId | string | A JustTCG card ID or UUID to look up. | | variantId | string | A JustTCG variant ID or UUID to look up. | | scryfallId | string | The Scryfall ID for the card (if applicable). | | mtgjsonId | string | The MTGJSON ID for the card (if applicable). | | query | string | A general search query for the card name. | | game | string | The name of the game to filter by (e.g., 'Pokemon'). | | set | string | The id of the set to filter by (e.g., 'the-first-chapter-disney-lorcana'). | | number | string | The number of the card within the set (e.g., '015'). | | updated_after | number | Unix timestamp (seconds) to filter results updated after this time. | | condition | string[] | An array of conditions to filter by. Supports fully spelled names or abbreviations. Full names: "Sealed", "Near Mint", "Lightly Played", "Moderately Played", "Heavily Played", "Damaged". Abbreviations: "S", "NM", "LP", "MP", "HP", "DMG". | | printing | string[] | An array of print types to filter by (e.g., ['Foil', '1st Edition']). | | include_price_history | boolean | Option to include price history in the response for matching variants. | | priceHistoryDuration | '7d' | '30d' | '90d' | '180d' | '1y' | Specify which timeframe to include in the priceHistory array. This parameter is ignored if include_price_history is set to false. | | include_statistics | '7d' | '30d' | '90d' | '1y' | 'allTime' | Specify which timeframe statistics to include in the response. Defaults to all timeframes. You can provide a comma-separated list (e.g., 7d,30d,1y) to include multiple statistics. | | include_null_prices | boolean | Option to include cards that currently have null prices. Defaults to 'false'. | | min_price | number | Filters results to include only cards where the current market price is greater than or equal to the provided value. | | orderBy | 'price' | '24h' | '7d' | '30d' | '90d' | The field to sort the results by. Default is 'price'. | | order | 'asc' | 'desc' | The sort order. Default is 'desc'. | | limit | number | The maximum number of results to return. Default is 20. PlanMaxFree20Starter100Professional100Enterprise200 | | offset | number | The number of results to skip for pagination. |

  • Returns: Promise<JustTCGApiResponse<Card[]>> (This response includes the pagination object).

.getByBatch(items)

Retrieves multiple specific cards and their variants in a single, efficient request. This is ideal for updating inventory prices.

  • Parameters: An array of BatchLookupItem objects.

| Parameter | Type | Max Object Length | Description | | :-------- | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------- | | items | BatchLookupItem[] | PlanMaxFree20Starter100Professional100Enterprise200 | An array of lookup objects. |

BatchLookupItem Object:

You can mix and match different identifier types in a single batch request. The lookup item can define any combination of identifiers and options.

{
  tcgplayerId?: string; // A TCGplayer product ID.
  tcgplayerSkuId?: string; // The TCGplayer SKU ID for a specific variant.
  cardId?: string;      // A JustTCG card ID or UUID.
  variantId?: string;   // A JustTCG variant ID or UUID.
  scryfallId?: string;  // The Scryfall ID for the card.
  mtgjsonId?: string;   // The MTGJSON ID for the card.
  printing?: string[];  // Optional: Filter by specific print types for this item.
  condition?: string[]; // Optional: Filter by specific conditions for this item. Accepts full names and abbreviations.
  updated_after?: number; // Optional: Only return items updated after this Unix timestamp (seconds).
  include_price_history?: boolean; // Optional: Include price history for matched variants.
  include_statistics?: ('7d'|'30d'|'90d'|'1y'|'allTime')[]; // Optional: Specific timeframes for statistics.
}
  • Returns: Promise<JustTCGApiResponse<Card[]>> (This response does not include the pagination object).

Response data Object (Card and Variant)

The get() and getByBatch() methods return an array of Card objects. Each card contains an array of its Variant objects.

Card Object:

{
  /** The unique slug identifier for the card. Will be renamed to `slug` in v2. */
  id: string;
  /** The UUID of the card. Recommended for stable identification. */
  uuid: string;
  /** The name of the card. */
  name: string;
  /** The game this card belongs to. */
  game: string;
  /** The set ID this card belongs to. */
  set: string;
  /** The set name this card belongs to (may be omitted for some responses). */
  set_name?: string;
  /** The card number within the set. */
  number: string | null;
  /** The rarity of the card. */
  rarity: string | null;
  /** The TCGPlayer ID for the card. */
  tcgplayerId: string | null;
  /** The Scryfall ID for the card, if applicable. */
  scryfallId: string | null;
  /** The MTGJSON ID for the card, if applicable. */
  mtgjsonId: string | null;
  /** Additional details about the card. */
  details?: string | null;
  /** The different variants of the card. */
  variants: Variant[];
}

Variant Object: (Contains detailed pricing)

{
  /** The unique slug identifier for this variant. Will be renamed to `slug` in v2. */
  id: string;
  /** The UUID of this variant. Recommended for stable identification. */
  uuid: string;
  /** The condition of the card variant (e.g., Near Mint). */
  condition: string;
  /** The printing type of the card variant (e.g., Foil, 1st Edition). */
  printing: string;
  /** The language of the card variant, if applicable. */
  language: string | null;
  /** The TCGPlayer SKU of the specific variant, if available. */
  tcgplayerSkuId?: string;
  /** The current price of the card variant in dollars. */
  price: number;
  /** The last time the price was updated, as an epoch timestamp in seconds. */
  lastUpdated: number; // Epoch seconds
  /** The percentage change in price over the last 24 hours. */
  priceChange24hr?: number | null; // Percentage

  // --- 7d stats ---
  /** The percentage change in price over the last 7 days. */
  priceChange7d?: number | null; // Percentage
  /** The average price over the last 7 days. */
  avgPrice?: number | null; // Dollars
  /** The price history entries over the last 7 days. */
  priceHistory?: PriceHistoryEntry[] | null;
  minPrice7d?: number | null; // Dollars
  maxPrice7d?: number | null; // Dollars
  stddevPopPrice7d?: number | null;
  covPrice7d?: number | null;
  iqrPrice7d?: number | null;
  trendSlope7d?: number | null;
  priceChangesCount7d?: number | null;

  // --- 30d stats ---
  priceChange30d?: number | null; // Percentage
  avgPrice30d?: number | null; // Dollars
  minPrice30d?: number | null; // Dollars
  maxPrice30d?: number | null; // Dollars
  stddevPopPrice30d?: number | null;
  covPrice30d?: number | null;
  iqrPrice30d?: number | null;
  trendSlope30d?: number | null;
  priceChangesCount30d?: number | null;
  priceRelativeTo30dRange?: number | null;

  // --- 90d stats ---
  priceChange90d?: number | null; // Percentage
  avgPrice90d?: number | null; // Dollars
  minPrice90d?: number | null; // Dollars
  maxPrice90d?: number | null; // Dollars
  stddevPopPrice90d?: number | null;
  covPrice90d?: number | null;
  iqrPrice90d?: number | null;
  trendSlope90d?: number | null;
  priceChangesCount90d?: number | null;
  priceRelativeTo90dRange?: number | null;

  // --- 1y stats ---
  minPrice1y?: number | null;
  maxPrice1y?: number | null;

  // --- All-time stats ---
  minPriceAllTime?: number | null;
  minPriceAllTimeDate?: string | null;
  maxPriceAllTime?: number | null;
  maxPriceAllTimeDate?: string | null;
}

PriceHistoryEntry Object:

{
  /** Epoch timestamp in seconds. */
  t: number;
  /** Price in dollars. */
  p: number;
}

Error Handling

The SDK surfaces errors in two primary ways: thrown exceptions for critical SDK issues and an error property on the response object for API issues.

1. Thrown Exceptions (SDK-level Errors)

Critical errors that happen at the SDK level will be thrown as a JavaScript Error. These must be wrapped in a try...catch block.

Common Causes:

  • Authentication Failure (401): The API key is missing.
  • Invalid Parameter Value: Providing an unknown value for a parameter like orderBy.

Example:

try {
  const client = new JustTCG();
  await client.v1.games.list();
} catch (error) {
  // This block will catch the error
  console.error((error as Error).message); // e.g., "Authentication error: API key is missing."
}

2. Response error Property (API-level Errors)

If a request is syntactically valid but fails API-level validation (e.g., an invalid lookup parameter), the API will often return a normal response object where the data is empty and the error and code properties are populated.

Common Causes:

  • Authentication Failure (401/403): The provided API key is invalid or disabled.
  • Not Found (404): The requested endpoint does not exist.
  • Rate Limit Exceeded (429): Your application is making too many requests.
  • Missing Required Parameters: Calling client.v1.sets.list() without the required game parameter.
  • Invalid Lookup Parameter: Providing an unknown value for a parameter like cardId.

Example:

const client = new JustTCG();
// Missing the required 'game' parameter
const response = await client.v1.sets.list();

if (response.error) {
  // This block will execute
  console.log(response.error); // "Required query parameter \"game\" is missing"
  console.log(response.code);  // "INVALID_REQUEST"
} else {
  // This data will be empty
  console.log(response.data);
}

Examples

You can find practical, runnable examples in the /examples directory of this repository.

To run an example, first ensure you have set your JUSTTCG_API_KEY environment variable.

# Example: Find the most valuable Lorcana cards from The First Chapter
export JUSTTCG_API_KEY="YOUR_API_KEY_HERE"
npx ts-node examples/find-most-valuable-lorcana-cards.ts

License

This SDK is licensed under the MIT License.