TCG Scanner API

Integrate card scanning and detection into your applications. Perfect for live pack opening platforms, inventory management, and streaming overlays.

Base URL:https://deckardgains.abacusai.app/api/v1

Quick Start

To use the API, you'll need an API key. Generate one by logging into your account and creating a key.

1. Generate an API Key

# Using your session cookie (log in first)
curl -X POST https://deckardgains.abacusai.app/api/v1/keys \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{"name": "My App", "permissions": ["scan:read", "scan:write", "webhook:manage"]}'

2. Make API Requests

# Create a scan session
curl -X POST https://deckardgains.abacusai.app/api/v1/sessions \
  -H "Authorization: Bearer tcgs_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Pack Opening Stream", "tcg_type": "MTG"}'

Authentication

All API requests require authentication via an API key passed in the Authorization header:

Authorization: Bearer tcgs_your_api_key_here
Permissions:
  • scan:read - Read sessions and detected cards
  • scan:write - Create sessions and add cards
  • webhook:manage - Register and manage webhooks
  • * - Full access

API Key Management

These endpoints require session authentication (you must be logged in).

Scan Sessions

Sessions group detected cards together. Create a session for each pack opening, box break, or scanning event.

Card Detection

Add detected cards to a session. Supports batch additions for efficiency.

Webhooks

Receive real-time notifications when cards are detected or sessions complete. Perfect for stream overlays and leaderboards.

Available Events

  • session.started - Fired when a new session begins
  • session.completed - Fired when a session is marked complete
  • card.detected - Fired for each individual card detection
  • card.batch_detected - Fired when multiple cards are added at once

Webhook Payload Format

// Headers sent with each webhook
X-TCG-Scanner-Signature: t=1708527600,v1=abc123...
X-TCG-Scanner-Event: card.detected
Content-Type: application/json

// Example payload for card.detected
{
  "event": "card.detected",
  "timestamp": "2026-02-21T12:00:00.000Z",
  "data": {
    "session_id": "clxyz789...",
    "card": {
      "id": "card_123",
      "name": "Black Lotus",
      "tcg_type": "MTG",
      "set_name": "Alpha",
      "rarity": "Rare",
      "price_usd": 50000.00,
      "confidence": 0.98,
      "quantity": 1,
      "image_url": "https://i.ytimg.com/vi/IS1PlCmW4RM/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLBXJ_rpW6PNnvTEXptCfgcln0VkDA"
    }
  }
}

Verifying Webhook Signatures

Always verify webhook signatures to ensure requests are from the TCG Scanner.

import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const [timestampPart, signaturePart] = signature.split(',');
  const timestamp = timestampPart.split('=')[1];
  const expectedSig = signaturePart.split('=')[1];
  
  const signedPayload = `${timestamp}.${payload}`;
  const computedSig = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(expectedSig),
    Buffer.from(computedSig)
  );
}

Full Integration Example

Here's a complete example of integrating the scanner with a pack opening stream:

// 1. Start a session when the stream begins
const session = await fetch('https://deckardgains.abacusai.app/api/v1/sessions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer tcgs_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Friday Night Box Break',
    tcg_type: 'MTG',
    metadata: { stream_id: 'twitch_123', shop: 'Card Kingdom' }
  })
}).then(r => r.json());

const sessionId = session.data.session_id;

// 2. When scanner detects a card, add it to the session
async function onCardDetected(cardData) {
  await fetch(`https://deckardgains.abacusai.app/api/v1/sessions/${sessionId}/cards`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer tcgs_your_api_key',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      cards: [{
        name: cardData.name,
        tcg_type: 'MTG',
        set_name: cardData.set,
        rarity: cardData.rarity,
        price_usd: cardData.price,
        confidence: cardData.confidence,
        image_url: cardData.image
      }]
    })
  });
}

// 3. Mark session complete when stream ends
await fetch(`https://deckardgains.abacusai.app/api/v1/sessions/${sessionId}`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer tcgs_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ status: 'COMPLETED' })
});

// 4. Get final results
const results = await fetch(`https://deckardgains.abacusai.app/api/v1/sessions/${sessionId}`, {
  headers: { 'Authorization': 'Bearer tcgs_your_api_key' }
}).then(r => r.json());

console.log(`Total value: $${results.data.total_value}`);
console.log(`Cards pulled: ${results.data.total_cards}`);

Rate Limits

  • Default: 1,000 requests per hour per API key
  • Webhook deliveries: Automatic retry with exponential backoff (max 3 attempts)
  • Webhooks disabled: After 10 consecutive failures, webhooks are automatically deactivated

Error Responses

StatusMeaning
400Bad Request - Invalid parameters
401Unauthorized - Missing or invalid API key
403Forbidden - Missing required permission
404Not Found - Resource doesn't exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error
{
  "error": "Missing permission: scan:write",
  "status": 403
}