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:
- Scheduler triggers (every 1 hour)
- Fetch prices from SteamAPIs.com
- Parse response - Extract item names and prices
- Query database - Get all active items for game
- Match items - Compare by name (exact match)
- Update prices - Save marketPrice and timestamp
- 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:
- Fetch inventory from Steam/SteamAPIs
- Parse descriptions - Extract item descriptions
- Detect phase - Scan name + description for phase keywords
- Store phase - Add to item data
- 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:
- Database marketPrice (if available and recent)
- SteamAPIs market data (if available)
- 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:
- ✅
STEAM_APIS_KEYin.env - ✅ API key is valid
- ✅ SteamAPIs.com service status
- ✅ 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:
- Item name contains phase info
- Item description parsed correctly
- 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:
- Scheduler is running
- Last update timestamp
- Items match by name exactly
- 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:
- Reduce update frequency (e.g., 2 hours instead of 1)
- Upgrade SteamAPIs.com plan
- Implement caching
- 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_KEYto.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