pisko999/cardmarket-php-sdk

Wrap Cardmarket API with PHP

Installs: 3

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 4

pkg:composer/pisko999/cardmarket-php-sdk

v2.3.0 2026-01-26 16:25 UTC

README

PHPUnit Tests PHP Version License

⚠️ API URL Change (v2.3.0+): Cardmarket has migrated to a new API endpoint. This SDK now uses apiv2.cardmarket.com instead of api.cardmarket.com. The old URL will be disabled by May 1, 2026. Update to v2.3.0+ to ensure continued functionality.

A comprehensive PHP SDK for the Cardmarket API 2.0, providing easy access to all marketplace features including stock management, order handling, wantslists, and more.

Note: This SDK is a fork of the original mamoot64/cardmarket-php-sdk by Nicolas Perussel, extended with additional features, bug fixes, and comprehensive test coverage.

Table of Contents

Requirements

  • PHP 8.1 or higher
  • Composer
  • Cardmarket API credentials (app token, app secret, access token, access secret)

Installation

composer require pisko999/cardmarket-php-sdk

Quick Start

use Pisko\CardMarket\Cardmarket;
use Pisko\CardMarket\HttpClient\HttpClientCreator;

// Initialize the HTTP client with your credentials
$httpCreator = new HttpClientCreator();
$httpCreator->setApplicationToken('your_app_token')
            ->setApplicationSecret('your_app_secret')
            ->setAccessToken('your_access_token')
            ->setAccessSecret('your_access_secret');

// Create the Cardmarket client
$cardmarket = new Cardmarket($httpCreator);

// Start using the API
$games = $cardmarket->games()->getGamesList();

Authentication

The SDK uses OAuth 1.0a authentication. You need four credentials from your Cardmarket developer account:

Credential Description
app_token Your application's public token
app_secret Your application's secret key
access_token User-specific access token
access_secret User-specific access secret

App Types

Cardmarket offers three types of applications:

  1. Dedicated App - For personal use, managing your own account
  2. Widget App - Runs within Cardmarket interface (limited API access)
  3. 3rd Party App - For services provided to other users

Note: Some endpoints are restricted based on app type. See the API documentation for details.

API Resources

Games & Expansions

// Get all available TCG games
$games = $cardmarket->games()->getGamesList();

// Get single game details
$game = $cardmarket->games()->getGame(1); // 1 = Magic: The Gathering

// Get all expansions for a game
$expansions = $cardmarket->expansions()->getExpansionsListByGame(1);

// Get expansion details
$expansion = $cardmarket->expansions()->getExpansion(1525);

// Get all cards in an expansion
$cards = $cardmarket->expansions()->getCardsListByExpansion(1525);

Game IDs

ID Game
1 Magic: The Gathering
2 World of Warcraft TCG
3 Yu-Gi-Oh!
5 The Spoils
6 Pokémon
7 Force of Will
8 Cardfight!! Vanguard
9 Final Fantasy TCG
10 Weiß Schwarz
11 Dragoborne
12 My Little Pony
13 Dragon Ball Super
15 Star Wars: Destiny

Products & Articles

// Get product details
$product = $cardmarket->products()->getProductDetails(273799);

// Find products by name
$products = $cardmarket->products()->findProducts('Black Lotus', 0, 100, [
    'idGame' => 1,
    'exact' => false
]);

// Get product list file (CSV)
$productList = $cardmarket->products()->getProductListFile();

// Get price guide
$priceGuide = $cardmarket->prices()->getPriceGuideFile();

// Get articles for a product (other users' offers)
$articles = $cardmarket->articles()->getArticlesByProduct(100569, [
    'minCondition' => 'NM',
    'isFoil' => true,
    'idLanguage' => 1
]);

// Get articles by user
$articles = $cardmarket->articles()->getArticlesByUser('SellerUsername', [
    'idGame' => 1,
    'start' => 0,
    'maxResults' => 100
]);

Stock Management

Reading Stock

// Get your stock (paginated, max 100 per request)
$stock = $cardmarket->stock()->getStock(0); // start from 0

// Get single article from stock
$article = $cardmarket->stock()->getStockArticle(142158699);

// Find articles by name
$articles = $cardmarket->stock()->findStockArticles('Pikachu', 6); // 6 = Pokemon

// Get articles for specific product
$articles = $cardmarket->stock()->getStockArticlesOfProduct(100569);

// Get articles currently in other users' carts
$inCarts = $cardmarket->stockInShoppingCarts()->getArticlesListInUsersShoppingCarts();

// Export stock as CSV file (deprecated but still functional)
$stockFile = $cardmarket->stock()->getStockFile(1, false, 1); // gameId, isSealed, languageId

Adding Articles to Stock

use Pisko\CardMarket\Entities\ArticleEntity;
use Pisko\CardMarket\Entities\ArticlesEntity;

// Create article entity
$article = new ArticleEntity([
    'idProduct' => 100569,
    'idLanguage' => 1,
    'comments' => 'Near Mint condition',
    'count' => 4,
    'price' => 2.50,
    'condition' => 'NM',
    'isFoil' => false,
    'isSigned' => false,
    'isAltered' => false
]);

// Add single article
$response = $cardmarket->addArticleStock()->add([$article->getArray()]);

// Add multiple articles (batch)
$articles = new ArticlesEntity([
    ['idProduct' => 100569, 'count' => 2, 'price' => 2.50, 'condition' => 'NM'],
    ['idProduct' => 100570, 'count' => 1, 'price' => 5.00, 'condition' => 'EX'],
]);
$response = $cardmarket->addArticleStock()->add($articles);

Updating Articles

// Update article properties (NOT quantity!)
$article = new ArticleEntity([
    'idArticle' => 142158699,
    'idLanguage' => 1,
    'comments' => 'Updated comment',
    'price' => 3.00,
    'condition' => 'NM'
]);

$response = $cardmarket->updateArticleStock()->add([$article->getArray()]);

Important: The regular PUT /stock endpoint cannot change quantities! Use changeQuantity() instead.

Changing Quantities

// Increase article quantity
$response = $cardmarket->stock()->increaseStock(142158699, 2); // Add 2 to existing count

// Decrease article quantity
$response = $cardmarket->stock()->decreaseStock(142158699, 1); // Remove 1 from count

Deleting Articles

$article = new ArticleEntity([
    'idArticle' => 142158699,
    'count' => 1  // Remove 1 from stock
]);

$response = $cardmarket->deleteArticleStock()->add([$article->getArray()]);

Stock Export (Async)

// Request stock export
$export = $cardmarket->stockExport()->askStockExport();

// Check export status
$status = $cardmarket->stockExport()->getStockExportStatus();

// Get specific export
$exportDetails = $cardmarket->stockExport()->getStockExport($exportId);

Order Management

// Get received orders (as seller)
$orders = $cardmarket->orders()->getReceivedOrders();

// Get sent orders (as buyer)
$orders = $cardmarket->orders()->getSentOrders();

// Filter orders by state
$orders = $cardmarket->orders()->getOrdersByActorAndState('seller', 'paid');
// States: bought, paid, sent, received, lost, cancelled, evaluated

// Get specific order
$order = $cardmarket->orders()->getOrder(123456);

// Change order state
use Pisko\CardMarket\Entities\OrderChangeStateEntity;

$cardmarket->orders()->changeOrderState(
    123456,                                  // Order ID
    OrderChangeStateEntity::STATE_CHANGE_SEND // Mark as sent
);

// Add tracking number
$cardmarket->orders()->setOrderTrackingNumber(123456, '1Z999AA10123456784');

// Evaluate order
use Pisko\CardMarket\Entities\EvaluationEntity;

$cardmarket->orders()->evaluateOrder(
    123456,                            // Order ID
    EvaluationEntity::GRADE_VERY_GOOD, // Overall grade
    EvaluationEntity::GRADE_VERY_GOOD, // Item description accuracy
    EvaluationEntity::GRADE_VERY_GOOD, // Packaging quality
    'Great seller, fast shipping!',    // Comment
    []                                 // Complaints (empty array)
);

Order States

State Description
bought Order placed, awaiting payment
paid Payment received
sent Shipped by seller
received Received by buyer
lost Package lost
cancelled Order cancelled
evaluated Order completed and evaluated

Evaluation Grades

Grade Constant Meaning
1 GRADE_VERY_GOOD Very Good
2 GRADE_GOOD Good
3 GRADE_NEUTRAL Neutral
4 GRADE_BAD Bad
10 GRADE_NA Not Applicable

Wantslists

// Get all wantslists
$wantslists = $cardmarket->wantslist()->getWantsLists();

// Get wantslist with items
$wantslist = $cardmarket->wantslist()->getWantsList(211682);

// Create new wantslist
$newList = $cardmarket->wantslist()->createWantsList('EDH Staples', 1); // 1 = MTG

// Rename wantslist
$cardmarket->wantslist()->renameWantsList(211682, 'Updated Name');

// Delete wantslist
$cardmarket->wantslist()->deleteWantsList(211682);

Managing Wantslist Items

use Pisko\CardMarket\Entities\WantslistItemEntity;
use Pisko\CardMarket\Entities\WantslistItemsEntity;

// Add items
$item = new WantslistItemEntity([
    'idProduct' => 100569,
    'count' => 4,
    'wishPrice' => 10,
    'idLanguage' => 1,
    'minCondition' => 'NM',
    'isFoil' => true
]);
$items = new WantslistItemsEntity([$item]);
$cardmarket->wantslist()->addItemsToWantsList(211682, $items);

// Edit items (requires idWant from existing item)
$item = new WantslistItemEntity([
    'idWant' => 12345,
    'count' => 2,
    'wishPrice' => 15
]);
$items = new WantslistItemsEntity([$item]);
$cardmarket->wantslist()->editItemsInWantsList(211682, $items);

// Delete items
$item = new WantslistItemEntity([
    'idWant' => 12345,
    'count' => 1
]);
$items = new WantslistItemsEntity([$item]);
$cardmarket->wantslist()->deleteItemsFromWantsList(211682, $items);

Shopping Cart

// Get current cart
$cart = $cardmarket->cart()->getCart();

// Add articles to cart (simple method)
$cardmarket->cart()->addToCart([
    ['idArticle' => 123456, 'amount' => 1],
    ['idArticle' => 123457, 'amount' => 2]
]);

// Remove articles from cart (simple method)
$cardmarket->cart()->removeFromCart([
    ['idArticle' => 123456, 'amount' => 1]
]);

// Empty entire cart
$cardmarket->cart()->emptyCart();

// Checkout
$cardmarket->cart()->checkout();

// Change shipping address
use Pisko\CardMarket\Entities\CartAddressEntity;

$address = new CartAddressEntity(
    'John Doe',           // name
    '',                   // extra (optional)
    '123 Main Street',    // street
    '12345',              // zip
    'Prague',             // city
    'CZ'                  // country code
);
$cardmarket->cart()->setCartAddress($address);

// Change shipping method (idReservation from cart response)
$cardmarket->cart()->setShippingMethod($idReservation, 2); // 2 = shipping method ID

Account Management

// Get current account info
$account = $cardmarket->account()->getAccount();

// Get specific user
$user = $cardmarket->users()->getUser('Username');

// Find users
$users = $cardmarket->users()->findUsers('searchterm');

// Messages
$threads = $cardmarket->messages()->getMessagesThread();
$thread = $cardmarket->messages()->getMessagesThreadByUser(123); // 123 = idOtherUser

// Send message
use Pisko\CardMarket\Entities\MessageEntity;

$message = new MessageEntity('Hello, I have a question about my order.');
$cardmarket->messages()->sendMessage(123, $message); // 123 = idOtherUser

// Coupons
$cardmarket->coupon()->redeemCoupons('COUPON-CODE');
// Or redeem multiple coupons
$cardmarket->coupon()->redeemCoupons(['COUPON-1', 'COUPON-2']);

Batch Operations

For operations that modify multiple items (add/update/delete stock), the SDK uses automatic batching:

// Async mode - accumulates items, sends when reaching 100
$cardmarket->addArticleStock()->add($articles, true);  // async = true
$cardmarket->addArticleStock()->add($moreArticles, true);

// Force send accumulated items
$response = $cardmarket->addArticleStock()->send();

// Sync mode (default) - sends immediately
$response = $cardmarket->addArticleStock()->add($articles);  // async = false (default)

Helpers

CsvStockFileHelper

use Pisko\CardMarket\Helpers\CsvStockFileHelper;

$stockFile = $cardmarket->stock()->getStockFile(1);
$helper = new CsvStockFileHelper($stockFile['stock']);

// Save to disk
$helper->storeStockFileOnDisk('./my-stock.csv');

GamesHelper

use Pisko\CardMarket\Helpers\GamesHelper;

// Check if game ID is valid
if (GamesHelper::isGame(1)) {
    echo "Valid game!";
}

// Use constants
$mtgId = GamesHelper::MTG;      // 1
$pokemonId = GamesHelper::PCG;  // 6

UserTypeHelper

use Pisko\CardMarket\Helpers\UserTypeHelper;

// User type constants
UserTypeHelper::PRIVATE_USER;      // 'private'
UserTypeHelper::COMMERCIAL_USER;   // 'commercial'
UserTypeHelper::POWERSELLER;       // 'powerseller'

Parameter Types

When passing search parameters to API methods, use the correct PHP types:

Boolean Parameters

Use PHP booleans (true/false), not strings. The SDK automatically converts them to the API format.

// ✅ Correct - use PHP booleans
$articles = $cardmarket->articles()->getArticles($productId, 0, 100, [
    'isFoil' => true,
    'isSigned' => false,
    'isAltered' => false,
]);

// ❌ Wrong - don't use strings
$articles = $cardmarket->articles()->getArticles($productId, 0, 100, [
    'isFoil' => 'true',   // Wrong!
    'isSigned' => 'false', // Wrong!
]);

Integer Parameters

Use PHP integers for IDs and numeric values:

$products = $cardmarket->products()->findProducts('Black Lotus', 0, 100, [
    'idGame' => 1,        // Integer
    'idLanguage' => 1,    // Integer
    'exact' => true,      // Boolean
]);

String Parameters

Use strings for conditions, comments, and text fields:

$articles = $cardmarket->articles()->getArticles($productId, 0, 100, [
    'minCondition' => 'NM',  // String: MT, NM, EX, GD, LP, PL, PO
]);

Condition Values

Value Meaning
MT Mint
NM Near Mint
EX Excellent
GD Good
LP Light Played
PL Played
PO Poor

Error Handling

use Pisko\CardMarket\Exception\HttpClientException;
use Pisko\CardMarket\Exception\HttpServerException;
use Pisko\CardMarket\Exception\HttpClientNotConfiguredException;
use Pisko\CardMarket\Exception\NonExistsResourceException;
use Pisko\CardMarket\Exception\UnknownErrorException;

try {
    $product = $cardmarket->products()->getProductDetails(999999999);
} catch (HttpClientException $e) {
    // 4xx errors (bad request, unauthorized, not found, etc.)
    echo "Client error: " . $e->getMessage();
    echo "Status code: " . $e->getCode();
} catch (HttpServerException $e) {
    // 5xx errors (server errors)
    echo "Server error: " . $e->getMessage();
} catch (HttpClientNotConfiguredException $e) {
    // Missing credentials
    echo "Configuration error: " . $e->getMessage();
}

HTTP Status Codes

Code Meaning
200 OK - Request successful
206 Partial Content - Paginated response, more data available
204 No Content - Request successful, no more data
400 Bad Request - Invalid parameters
401 Unauthorized - Invalid credentials
403 Forbidden - Access denied
404 Not Found - Resource doesn't exist
500+ Server Error - Cardmarket server issue

Known API Limitations

The following are known issues or limitations in the Cardmarket API itself (not SDK bugs):

Messages API

Method Issue
findMessages() Endpoint broken - Returns HTTP 400 "This feature is currently unavailable" but marks all unread messages as read anyway! Do not use.
deleteMessagesByUser() Does not delete messages - API returns 200 OK but messages remain. Use deleteOneMessageByUser() to delete individual messages instead.

Wantslists API

Method Issue
createWantslist() Name length limit - Wantslist names are limited to approximately 8 characters. Longer names may be truncated or rejected.

Custom Resources

Extend the SDK with your own resources:

namespace App\CardmarketResources;

use Pisko\CardMarket\Resources\HttpCaller;

class MyCustomResource extends HttpCaller
{
    public function getExpensiveCards(int $gameId): array
    {
        $products = $this->get('/products/find?idGame=' . $gameId . '&minPrice=100');
        // Custom logic here
        return $products;
    }
}

Register and use:

$cardmarket->registerResources('custom', MyCustomResource::class);
$expensiveCards = $cardmarket->custom()->getExpensiveCards(1);

Note: You cannot override default resource names.

Breaking Changes

Version 2.0.0 (January 2026)

Removed Features

  1. isPlayset property removed

    • As of November 11, 2024, Cardmarket no longer supports playsets
    • Removed from: ArticleEntity, WantslistItemEntity, ArticlesResource
    • Migration: Remove any isPlayset parameters from your code
  2. Captcha endpoint removed

    • The /captcha endpoint was deprecated in Cardmarket API 2.0
    • Removed: CaptchaResource class and captcha() method
    • Migration: Remove any captcha-related code

Method Renames

  • StockExport()stockExport() (camelCase consistency)

Fixed Bugs

  • Fixed wrong endpoint in getStockArticlesOfProduct() (/stock/%d/stock/products/%d)
  • Fixed switch case bug in HTTP error handling
  • Fixed hasError() return type (intbool)
  • Added XML escaping to all entity XML outputs for security
  • Added proper null handling for API response headers

Testing

# Clone repository
git clone git@github.com:pisko999/cardmarket-php-sdk.git
cd cardmarket-php-sdk

# Install dependencies
composer install

# Run tests
composer test

# Run static analysis
composer stan

# Check coding standards
composer cs-check

# Fix coding standards
composer cs-fix

# Run all checks (cs-check, stan, test)
composer check

# Run tests with coverage
composer test-coverage-html

API Documentation

Complete API documentation is available in the docs/ folder:

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Credits