# 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:** ```javascript // 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:** ```json { "data": { "AK-47 | Redline (Field-Tested)": { "prices": { "7": 42.50, "30": 41.80, "all_time": 45.00 } } } } ``` ### 3. Database Storage **Item Model Fields:** ```javascript { 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: ```env # 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`: ```env ADMIN_STEAM_IDS=76561198000000000,76561198111111111 ``` **Option B: Staff Level** Update user in database: ```javascript 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):** ```javascript // Runs every 1 hour automatically pricingService.scheduleUpdates(60 * 60 * 1000); ``` **Manual via API:** ```bash POST /api/admin/prices/schedule { "intervalMinutes": 60 } ``` **Disable in Development:** ```env # 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 ```http POST /api/admin/prices/update Content-Type: application/json Cookie: accessToken=your_jwt_token { "game": "cs2" // "cs2", "rust", or "all" } ``` **Response:** ```json { "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 ```http GET /api/admin/prices/status Cookie: accessToken=your_jwt_token ``` **Response:** ```json { "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 ```http GET /api/admin/prices/missing?game=cs2&limit=50 Cookie: accessToken=your_jwt_token ``` **Response:** ```json { "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 ```http POST /api/admin/prices/estimate Content-Type: application/json Cookie: accessToken=your_jwt_token { "itemId": "item_id_here" } ``` **Response:** ```json { "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 ```http 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 ```http GET /api/admin/stats Cookie: accessToken=your_jwt_token ``` **Response:** ```json { "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:** ```javascript // 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:** ```javascript 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:** ```bash # 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:** ```json { "success": true, "message": "Price update completed", "data": { "cs2": { "success": true, "updated": 142, "notFound": 8 } } } ``` ### 2. Test Phase Detection **Load item with Doppler:** ```javascript // 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:** ```javascript // 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:** ```env 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 ```javascript // 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:** ```bash # 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:** ```javascript // 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:** ```bash # 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:** ```javascript // 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 ```javascript // 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 ```javascript // 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 ```javascript 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