Files
TurboTrades/PRICING_SYSTEM.md
2026-01-10 04:57:43 +00:00

15 KiB

Pricing System & Phase Detection Guide

Complete guide for the automated pricing system using SteamAPIs.com, phase detection for Doppler items, and hourly price updates.


🎯 Overview

The pricing system automatically fetches and updates market prices for CS2 and Rust items every hour using SteamAPIs.com. It includes:

  • Phase Detection - Automatically detects Doppler phases (Ruby, Sapphire, Phase 1-4, etc.)
  • Market Price Storage - Stores prices in database for fast access
  • Automatic Updates - Scheduled hourly updates (configurable)
  • Manual Triggers - Admin panel for manual price updates
  • Estimation Fallback - Smart price estimation when market data unavailable

📊 Features

1. Phase Detection

Automatically detects Doppler and Gamma Doppler phases from item names and descriptions:

Supported Phases:

  • Ruby (highest value)
  • Sapphire (highest value)
  • Black Pearl (rare)
  • Emerald (Gamma Doppler)
  • Phase 1
  • Phase 2 (popular)
  • Phase 3
  • Phase 4 (popular)

How It Works:

// Example detection from item name/description
"★ Karambit | Doppler (Factory New) - Ruby"  Phase: "Ruby"
"★ M9 Bayonet | Doppler (Minimal Wear) - Phase 2"  Phase: "Phase 2"

Phase Multipliers (Price Impact):

  • Ruby: 3.5x base price
  • Sapphire: 3.8x base price
  • Emerald: 4.0x base price
  • Black Pearl: 2.5x base price
  • Phase 2: 1.3x base price
  • Phase 4: 1.2x base price
  • Phase 1: 1.0x base price
  • Phase 3: 0.95x base price

2. Market Price Fetching

Source: SteamAPIs.com /market/items/{AppID} endpoint

Supported Games:

  • CS2 (AppID: 730)
  • Rust (AppID: 252490)

Price Data:

  • Uses 30-day average price (most stable)
  • Currency: USD
  • Updates every hour
  • Caches last update timestamp

Example API Call:

GET https://api.steamapis.com/market/items/730?api_key=YOUR_KEY

Response Format:

{
  "data": {
    "AK-47 | Redline (Field-Tested)": {
      "prices": {
        "7": 42.50,
        "30": 41.80,
        "all_time": 45.00
      }
    }
  }
}

3. Database Storage

Item Model Fields:

{
  name: String,              // Item name (used for price matching)
  price: Number,             // Seller's listing price
  marketPrice: Number,       // Current market price from SteamAPIs
  priceUpdatedAt: Date,      // Last price update timestamp
  phase: String,             // Doppler phase (if applicable)
  wear: String,              // fn, mw, ft, ww, bs
  statTrak: Boolean,
  souvenir: Boolean
}

4. Price Estimation

When market data is unavailable, the system uses intelligent estimation:

Factors Considered:

  • Item name patterns (knives, gloves, high-tier skins)
  • Wear condition multipliers
  • Phase multipliers
  • StatTrak multiplier (1.5x)
  • Souvenir multiplier (1.3x)

Wear Multipliers:

  • Factory New (FN): 1.0x
  • Minimal Wear (MW): 0.85x
  • Field-Tested (FT): 0.70x
  • Well-Worn (WW): 0.55x
  • Battle-Scarred (BS): 0.40x

🔧 Setup & Configuration

1. Environment Variables

Add to .env file:

# Steam API Key (SteamAPIs.com)
STEAM_APIS_KEY=your_steamapis_key_here
STEAM_API_KEY=fallback_key_here

# Admin Configuration
ADMIN_STEAM_IDS=76561198000000000,76561198111111111

# Enable automatic price updates (optional in dev)
ENABLE_PRICE_UPDATES=true

2. Admin Access

Option A: Steam ID Whitelist Add admin Steam IDs to .env:

ADMIN_STEAM_IDS=76561198000000000,76561198111111111

Option B: Staff Level Update user in database:

db.users.updateOne(
  { steamId: "76561198000000000" },
  { $set: { staffLevel: 3 } }
)

Admin Levels:

  • 0: Regular user
  • 1: Moderator
  • 2: Staff
  • 3+: Admin (has pricing access)

3. Start Price Updates

Automatic (on server start):

// Runs every 1 hour automatically
pricingService.scheduleUpdates(60 * 60 * 1000);

Manual via API:

POST /api/admin/prices/schedule
{
  "intervalMinutes": 60
}

Disable in Development:

# Don't set ENABLE_PRICE_UPDATES or set to false
ENABLE_PRICE_UPDATES=false

📡 API Endpoints

Admin Endpoints (Require Authentication + Admin Access)

1. Trigger Price Update

POST /api/admin/prices/update
Content-Type: application/json
Cookie: accessToken=your_jwt_token

{
  "game": "cs2"  // "cs2", "rust", or "all"
}

Response:

{
  "success": true,
  "message": "Price update completed",
  "data": {
    "cs2": {
      "success": true,
      "game": "cs2",
      "total": 150,
      "updated": 142,
      "notFound": 8,
      "errors": 0,
      "timestamp": "2024-01-10T12:00:00.000Z"
    }
  }
}

2. Get Price Update Status

GET /api/admin/prices/status
Cookie: accessToken=your_jwt_token

Response:

{
  "success": true,
  "status": {
    "cs2": {
      "lastUpdate": "2024-01-10T11:00:00.000Z",
      "needsUpdate": false,
      "stats": {
        "total": 150,
        "withMarketPrice": 142,
        "avgMarketPrice": 45.50,
        "minMarketPrice": 0.50,
        "maxMarketPrice": 8999.99
      }
    },
    "rust": {
      "lastUpdate": "2024-01-10T11:00:00.000Z",
      "needsUpdate": false,
      "stats": {
        "total": 50,
        "withMarketPrice": 45,
        "avgMarketPrice": 25.30
      }
    }
  }
}

3. Get Items Without Prices

GET /api/admin/prices/missing?game=cs2&limit=50
Cookie: accessToken=your_jwt_token

Response:

{
  "success": true,
  "total": 8,
  "items": [
    {
      "_id": "item_id",
      "name": "AK-47 | Redline (Field-Tested)",
      "game": "cs2",
      "category": "rifles",
      "rarity": "rare",
      "wear": "ft",
      "phase": null,
      "seller": {
        "username": "User123"
      }
    }
  ]
}

4. Estimate Price for Specific Item

POST /api/admin/prices/estimate
Content-Type: application/json
Cookie: accessToken=your_jwt_token

{
  "itemId": "item_id_here"
}

Response:

{
  "success": true,
  "message": "Price estimated and updated",
  "item": {
    "id": "item_id",
    "name": "AK-47 | Redline (Field-Tested)",
    "marketPrice": 42.50,
    "priceUpdatedAt": "2024-01-10T12:00:00.000Z"
  }
}

5. Schedule Price Updates

POST /api/admin/prices/schedule
Content-Type: application/json
Cookie: accessToken=your_jwt_token

{
  "intervalMinutes": 60
}

Options:

  • Minimum: 15 minutes
  • Maximum: 1440 minutes (24 hours)
  • Default: 60 minutes (1 hour)

6. Get System Statistics

GET /api/admin/stats
Cookie: accessToken=your_jwt_token

Response:

{
  "success": true,
  "stats": {
    "items": {
      "total": 250,
      "active": 200,
      "sold": 50
    },
    "users": {
      "total": 1500
    },
    "marketplace": {
      "totalValue": 125000.00,
      "totalRevenue": 75000.00
    },
    "recentSales": [...]
  }
}

🔄 How It Works

Automatic Price Updates

Flow:

  1. Scheduler triggers (every 1 hour)
  2. Fetch prices from SteamAPIs.com
  3. Parse response - Extract item names and prices
  4. Query database - Get all active items for game
  5. Match items - Compare by name (exact match)
  6. Update prices - Save marketPrice and timestamp
  7. Log results - Report success/failures

Example Log Output:

⏰ Scheduling automatic price updates every 60 minutes
📊 Fetching CS2 market prices...
✅ Fetched 5000 prices for CS2
🔄 Updating database prices for CS2...
✅ Price update complete for CS2:
   - Total items: 150
   - Updated: 142
   - Not found: 8
   - Errors: 0

Phase Detection in Inventory

When user loads Sell page:

  1. Fetch inventory from Steam/SteamAPIs
  2. Parse descriptions - Extract item descriptions
  3. Detect phase - Scan name + description for phase keywords
  4. Store phase - Add to item data
  5. Calculate price - Apply phase multipliers

Example:

// Item from Steam inventory
{
  name: "★ Karambit | Doppler (Factory New)",
  descriptions: [
    { value: "Phase 2" },
    { value: "Rare Special Item" }
  ]
}

// After phase detection
{
  name: "★ Karambit | Doppler (Factory New)",
  phase: "Phase 2",
  estimatedPrice: 520.00  // Base 400 * 1.3 (Phase 2 multiplier)
}

Price Calculation

Priority Order:

  1. Database marketPrice (if available and recent)
  2. SteamAPIs market data (if available)
  3. Estimation algorithm (fallback)

Calculation Steps:

let price = basePrice;

// 1. Apply wear multiplier
if (wear) {
  price *= wearMultipliers[wear];
}

// 2. Apply phase multiplier
if (phase) {
  price *= phaseMultipliers[phase];
}

// 3. Apply StatTrak multiplier
if (statTrak) {
  price *= 1.5;
}

// 4. Apply Souvenir multiplier
if (souvenir) {
  price *= 1.3;
}

return Math.round(price * 100) / 100;

🧪 Testing

1. Test Price Fetching

Via Admin API:

# Get auth token first (login via Steam)
# Then trigger update

curl -X POST http://localhost:3000/api/admin/prices/update \
  -H "Content-Type: application/json" \
  -H "Cookie: accessToken=YOUR_TOKEN" \
  -d '{"game": "cs2"}'

Expected Response:

{
  "success": true,
  "message": "Price update completed",
  "data": {
    "cs2": {
      "success": true,
      "updated": 142,
      "notFound": 8
    }
  }
}

2. Test Phase Detection

Load item with Doppler:

// In Sell page, select a Doppler knife
// Check console logs or item data

console.log(item.phase); // Should show "Ruby", "Phase 2", etc.

3. Verify Database Updates

MongoDB Shell:

// Check items with market prices
db.items.find({
  marketPrice: { $exists: true, $ne: null }
}).count();

// Check recent price updates
db.items.find({
  priceUpdatedAt: { $gte: new Date(Date.now() - 3600000) }
});

// Check items with phases
db.items.find({
  phase: { $ne: null }
});

4. Test Scheduled Updates

Enable in development:

ENABLE_PRICE_UPDATES=true

Watch logs:

⏰ Starting automatic price update scheduler...
📊 Fetching CS2 market prices...
✅ Fetched 5000 prices for CS2
🔄 Updating database prices for CS2...
✅ Price update complete

📈 Monitoring

Check Price Update Status

Via Admin Dashboard:

GET /api/admin/prices/status

Look for:

  • Last update timestamp
  • Number of items with prices
  • Items missing prices
  • Average market prices

Check Logs

Successful Update:

✅ Fetched 5000 prices for CS2
✅ Price update complete for CS2:
   - Total items: 150
   - Updated: 142

Failures:

❌ Error fetching market prices for cs2: 429 Rate limit exceeded
❌ Failed to update item AK-47 | Redline: Not found in market data

Database Health Check

// Check price coverage
db.items.aggregate([
  {
    $group: {
      _id: "$game",
      total: { $sum: 1 },
      withPrice: {
        $sum: { $cond: [{ $ne: ["$marketPrice", null] }, 1, 0] }
      }
    }
  }
]);

// Output:
// { _id: "cs2", total: 150, withPrice: 142 }
// { _id: "rust", total: 50, withPrice: 45 }

🐛 Troubleshooting

Issue: No Prices Being Fetched

Check:

  1. STEAM_APIS_KEY in .env
  2. API key is valid
  3. SteamAPIs.com service status
  4. Rate limits not exceeded

Fix:

# Verify API key
curl "https://api.steamapis.com/market/items/730?api_key=YOUR_KEY"

# Check backend logs
# Should see: "📊 Fetching CS2 market prices..."

Issue: Phase Not Detected

Check:

  1. Item name contains phase info
  2. Item description parsed correctly
  3. Phase keywords match exactly

Debug:

// Add logging in inventory route
console.log("Item name:", item.name);
console.log("Descriptions:", item.descriptions);
console.log("Detected phase:", item.phase);

Issue: Prices Not Updating

Check:

  1. Scheduler is running
  2. Last update timestamp
  3. Items match by name exactly
  4. No errors in logs

Fix:

# Manually trigger update
POST /api/admin/prices/update

# Check status
GET /api/admin/prices/status

# Check missing prices
GET /api/admin/prices/missing

Issue: Rate Limit Exceeded

Error: 429 Rate limit exceeded

Solutions:

  1. Reduce update frequency (e.g., 2 hours instead of 1)
  2. Upgrade SteamAPIs.com plan
  3. Implement caching
  4. Batch updates

Configure:

// Update every 2 hours instead
pricingService.scheduleUpdates(120 * 60 * 1000);

🚀 Production Recommendations

1. Monitoring

  • Set up alerts for failed price updates
  • Monitor API usage and rate limits
  • Track price coverage percentage
  • Log all admin actions

2. Optimization

  • Cache price data in Redis (5-10 minutes)
  • Batch API requests when possible
  • Only update changed prices
  • Use webhooks if available

3. Backup Strategy

  • Keep historical price data
  • Store last N successful fetches
  • Fallback to estimation if API down
  • Manual override capability

4. Security

  • Restrict admin endpoints to IP whitelist
  • Log all price modifications
  • Implement audit trail
  • Rate limit admin endpoints

📚 API Reference

SteamAPIs.com Endpoints

Market Items:

GET /market/items/{appId}?api_key={key}

Rate Limits:

  • Free: 100,000 requests/month
  • Pro: Higher limits available

Documentation: https://steamapis.com/docs


🎓 Examples

Example 1: Manual Price Update

// Admin triggers update for CS2
const response = await fetch('/api/admin/prices/update', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  credentials: 'include',
  body: JSON.stringify({ game: 'cs2' })
});

const result = await response.json();
console.log(`Updated ${result.data.cs2.updated} items`);

Example 2: Phase Detection

// Service method
const phase = pricingService.detectPhase(
  "★ Karambit | Doppler (Factory New)",
  "Phase 2 pattern with pink/purple playside"
);

console.log(phase); // "Phase 2"

Example 3: Price Estimation

const price = await pricingService.estimatePrice({
  name: "AK-47 | Redline (Field-Tested)",
  wear: "ft",
  phase: null,
  statTrak: false,
  souvenir: false
});

console.log(price); // 42.50

Checklist

Setup:

  • Added STEAM_APIS_KEY to .env
  • Configured admin Steam IDs or staff levels
  • Tested API key with manual request
  • Enabled price updates in environment

Testing:

  • Manual price update works
  • Automatic updates scheduled
  • Phase detection working
  • Database storing prices correctly
  • Admin endpoints accessible

Production:

  • Monitoring configured
  • Rate limits understood
  • Backup strategy in place
  • Security measures implemented

Last Updated: 2024
Version: 1.0
Maintained by: TurboTrades Team