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

14 KiB

Steam Bot Setup Guide

🤖 Overview

The Steam bot system handles trade offers for buying items from users. When a user sells items, instead of immediately crediting funds, the system:

  1. Creates a trade offer via Steam bot
  2. Tracks trade state (pending, accepted, declined, etc.)
  3. 💰 Credits user balance ONLY after trade is accepted
  4. 🔄 Handles failures, expirations, and retries

📋 Prerequisites

1. Steam Bot Account

You need a separate Steam account for the bot:

  • Account with Steam Mobile Authenticator enabled
  • Public inventory
  • Valid trade URL
  • API key from https://steamcommunity.com/dev/apikey
  • Not limited (must have spent $5+ on Steam)
  • Trade cooldown period expired (if newly set up)

2. Required Packages

Already installed in package.json:

{
  "steam-user": "^5.0.0",
  "steamcommunity": "^3.47.0",
  "steam-tradeoffer-manager": "^2.10.6",
  "steam-totp": "^2.1.1"
}

Install if needed:

npm install steam-user steamcommunity steam-tradeoffer-manager steam-totp

🔐 Getting Steam Bot Credentials

Step 1: Get Shared Secret & Identity Secret

  1. Enable Steam Mobile Authenticator on bot account

  2. Use one of these tools to extract secrets:

  3. You'll need:

    • shared_secret - For generating 2FA codes
    • identity_secret - For confirming trades

Step 2: Get Steam API Key

  1. Go to: https://steamcommunity.com/dev/apikey
  2. Register domain: turbotrades.com (or your domain)
  3. Copy the API key

Step 3: Get Bot Trade URL

  1. Login to bot account
  2. Go to: https://steamcommunity.com/id/me/tradeoffers/privacy
  3. Copy the trade URL (looks like: https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=XXXXXXXX)

⚙️ Configuration

Environment Variables

Add to your .env file:

# Steam Bot Credentials
STEAM_BOT_USERNAME=your_bot_username
STEAM_BOT_PASSWORD=your_bot_password
STEAM_BOT_SHARED_SECRET=your_shared_secret_here
STEAM_BOT_IDENTITY_SECRET=your_identity_secret_here

# Steam API
STEAM_API_KEY=your_steam_api_key

# Bot Trade URL
STEAM_BOT_TRADE_URL=https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=XXXXXXXX

# Optional: Bot Settings
STEAM_BOT_POLL_INTERVAL=30000
STEAM_BOT_AUTO_START=true

Security Notes

  • ⚠️ NEVER commit .env to git
  • ⚠️ Keep secrets secure
  • ⚠️ Use different account from your personal Steam
  • ⚠️ Enable Steam Guard on bot account
  • ⚠️ Use strong password

🚀 Starting the Bot

Bot starts automatically when backend launches if STEAM_BOT_AUTO_START=true

npm run dev

You'll see:

🔐 Logging into Steam...
✅ Steam bot logged in successfully
✅ Steam web session established
🤖 Steam bot ready for trades

Manual Start

import { getSteamBot } from './services/steamBot.js';

const bot = getSteamBot();
await bot.login();

console.log('Bot ready:', bot.isOnline());

🔄 How It Works

User Sells Items Flow

1. User selects items on Sell page
2. User clicks "Sell Selected Items"
   ↓
3. Backend creates Trade record (state: pending)
   - Does NOT credit balance yet
   ↓
4. Steam bot creates trade offer
   - Requests items from user
   - User sees trade offer in Steam
   ↓
5. User accepts trade in Steam app
   ↓
6. Bot receives "trade accepted" event
   ↓
7. Backend:
   - Updates Trade state to "accepted"
   - Creates Transaction record
   - Credits user balance
   - Updates WebSocket
   ↓
8. User sees balance update in UI

Trade States

State Description User Balance Can Retry
pending Trade offer sent, waiting for user Not credited Yes
accepted User accepted, items received Credited No
declined User declined the offer Not credited ⚠️ Maybe
expired Trade offer expired (10min timeout) Not credited Yes
canceled Trade was canceled Not credited Yes
failed Technical error occurred Not credited Yes
escrow Trade in Steam escrow Not credited Wait

📊 Database Schema

Trade Model

{
  offerId: String,           // Steam trade offer ID
  userId: ObjectId,          // User who's selling
  steamId: String,           // User's Steam ID
  state: String,             // pending, accepted, declined, etc.
  items: [{
    assetId: String,
    name: String,
    price: Number,
    image: String,
    // ... item details
  }],
  totalValue: Number,        // Total price of all items
  fee: Number,               // Platform fee (e.g., 5%)
  feePercentage: Number,     // Fee percentage
  userReceives: Number,      // Amount user gets (after fees)
  tradeUrl: String,          // User's trade URL
  tradeOfferUrl: String,     // Link to view offer on Steam
  sentAt: Date,              // When trade was sent
  acceptedAt: Date,          // When user accepted
  completedAt: Date,         // When balance was credited
  expiresAt: Date,           // When trade expires (10min)
  transactionId: ObjectId,   // Transaction created after acceptance
  sessionId: ObjectId,       // User's session
  errorMessage: String,      // If failed
  retryCount: Number,        // How many times retried
  metadata: Mixed            // Additional data
}

🎮 Bot Events

The bot emits events you can listen to:

const bot = getSteamBot();

// Bot is ready
bot.on('ready', () => {
  console.log('Bot is ready!');
});

// Trade accepted
bot.on('tradeAccepted', async (offer, tradeData) => {
  console.log('Trade accepted:', offer.id);
  // Credit user balance here
});

// Trade declined
bot.on('tradeDeclined', async (offer, tradeData) => {
  console.log('Trade declined:', offer.id);
  // Notify user
});

// Trade expired
bot.on('tradeExpired', async (offer, tradeData) => {
  console.log('Trade expired:', offer.id);
  // Can retry or cancel
});

// Bot error
bot.on('error', (err) => {
  console.error('Bot error:', err);
});

// Bot disconnected
bot.on('disconnected', () => {
  console.warn('Bot disconnected, will reconnect...');
});

🛠️ API Endpoints

Create Trade Offer

POST /api/trade/create
Authorization: Bearer <token>

{
  "items": [
    {
      "assetId": "123456789",
      "name": "AK-47 | Redline (Field-Tested)",
      "price": 12.50,
      "image": "https://...",
      // ... other item data
    }
  ]
}

Response:

{
  "success": true,
  "trade": {
    "id": "trade_id",
    "offerId": "steam_offer_id",
    "state": "pending",
    "totalValue": 12.50,
    "userReceives": 11.88,
    "items": [...],
    "tradeOfferUrl": "https://steamcommunity.com/tradeoffer/...",
    "expiresAt": "2024-01-10T12:10:00Z"
  },
  "message": "Trade offer sent! Check your Steam app to accept."
}

Get Trade Status

GET /api/trade/:tradeId
Authorization: Bearer <token>

Response:

{
  "success": true,
  "trade": {
    "id": "trade_id",
    "offerId": "steam_offer_id",
    "state": "accepted",
    "totalValue": 12.50,
    "userReceives": 11.88,
    "acceptedAt": "2024-01-10T12:05:00Z",
    "timeElapsed": "5m ago"
  }
}

Cancel Trade

POST /api/trade/:tradeId/cancel
Authorization: Bearer <token>

Retry Trade

POST /api/trade/:tradeId/retry
Authorization: Bearer <token>

🔧 Bot Management

Check Bot Status

const bot = getSteamBot();

const health = bot.getHealth();
console.log(health);
// {
//   isReady: true,
//   isLoggedIn: true,
//   activeTradesCount: 5,
//   username: "bot_username"
// }

Get Active Trades

const activeTrades = bot.getActiveTrades();
console.log(`${activeTrades.length} trades active`);

Cancel All Pending Trades

const pendingTrades = await Trade.getPendingTrades();

for (const trade of pendingTrades) {
  if (trade.isExpired) {
    await bot.cancelTradeOffer(trade.offerId);
    await trade.markAsExpired();
  }
}

🧪 Testing

Test Bot Login

node -e "import('./services/steamBot.js').then(async m => {
  const bot = m.getSteamBot();
  await bot.login();
  console.log('Bot logged in:', bot.isOnline());
  bot.logout();
  process.exit(0);
})"

Test Trade Creation

const bot = getSteamBot();
await bot.login();

const result = await bot.createTradeOffer({
  tradeUrl: "https://steamcommunity.com/tradeoffer/new/?partner=XXX&token=XXX",
  itemsToReceive: [
    { assetid: "123456789", appid: 730, contextid: 2 }
  ],
  message: "Test trade offer"
});

console.log('Trade created:', result);

📈 Monitoring

Database Queries

// Get all pending trades
const pending = await Trade.find({ state: 'pending' });

// Get expired trades
const expired = await Trade.getExpiredTrades();

// Get trade stats
const stats = await Trade.getStats();
console.log(`
  Total trades: ${stats.total}
  Accepted: ${stats.accepted}
  Pending: ${stats.pending}
  Declined: ${stats.declined}
`);

// Get user's trades
const userTrades = await Trade.getUserTrades(userId);

Admin Panel Integration

Add to admin panel:

  • View pending trades
  • Cancel stale trades
  • Retry failed trades
  • View trade statistics
  • Bot health status

🐛 Troubleshooting

Bot Won't Login

Check:

  • Username and password correct
  • Shared secret is valid
  • Steam account not limited
  • No active VAC ban
  • No trade cooldown

Solution:

# Test credentials
node -e "console.log('Username:', process.env.STEAM_BOT_USERNAME)"
node -e "console.log('Has password:', !!process.env.STEAM_BOT_PASSWORD)"
node -e "console.log('Has shared secret:', !!process.env.STEAM_BOT_SHARED_SECRET)"

Trades Not Confirming

Check:

  • Identity secret is correct
  • Mobile authenticator is active
  • Bot has trade URL

Solution:

  • Manually confirm in Steam app first time
  • Check if identity secret is correct
  • Regenerate secrets if needed

Trades Stuck in Pending

Reasons:

  • User hasn't accepted yet
  • Trade expired (10 minutes)
  • Steam API issues
  • User's inventory is private

Solution:

// Cancel expired trades
const expired = await Trade.find({
  state: 'pending',
  expiresAt: { $lt: new Date() }
});

for (const trade of expired) {
  await bot.cancelTradeOffer(trade.offerId);
  await trade.markAsExpired();
}

Bot Keeps Disconnecting

Check:

  • Network connection stable
  • Steam not under maintenance
  • No rate limiting

Solution:

  • Implement auto-reconnect (already built-in)
  • Use connection pooling
  • Monitor logs for error patterns

🔒 Security Best Practices

1. Secure Credentials

  • Never hardcode credentials
  • Use environment variables
  • Keep .env out of git
  • Rotate secrets regularly

2. Trade Validation

  • Verify user owns items before creating trade
  • Check item values match database
  • Validate trade URLs
  • Prevent duplicate trades

3. Rate Limiting

  • Limit trades per user per hour
  • Limit total trades per minute
  • Queue trades during high load

4. Monitoring

  • Log all trade events
  • Alert on failed trades
  • Track bot uptime
  • Monitor Steam API status

📊 Performance Optimization

Trade Queue System

For high volume, implement trade queue:

// Redis-based queue
import Bull from 'bull';

const tradeQueue = new Bull('trades', {
  redis: { host: 'localhost', port: 6379 }
});

tradeQueue.process(async (job) => {
  const { userId, items } = job.data;
  return await createTradeOffer(userId, items);
});

// Add to queue
await tradeQueue.add({ userId, items }, {
  attempts: 3,
  backoff: {
    type: 'exponential',
    delay: 2000
  }
});

Retry Strategy

async function createTradeWithRetry(data, maxRetries = 3) {
  let lastError;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await bot.createTradeOffer(data);
    } catch (error) {
      lastError = error;
      await sleep(Math.pow(2, i) * 1000); // Exponential backoff
    }
  }
  
  throw lastError;
}

🎯 Next Steps

Phase 1: Basic Setup (You are here)

  • Install packages
  • Create bot service
  • Create Trade model
  • Configure environment variables
  • Test bot login

Phase 2: Integration

  • Update sell endpoint to create trades
  • Add trade event handlers
  • Credit balance on acceptance
  • Add trade status polling

Phase 3: Frontend

  • Show trade status in UI
  • Add "View Trade" button
  • Show pending trades list
  • Add trade notifications

Phase 4: Admin Tools

  • Bot health dashboard
  • Trade management panel
  • Retry/cancel controls
  • Statistics and reports

Phase 5: Advanced

  • Trade queue system
  • Multiple bot support
  • Automatic retries
  • Fraud detection

📚 Additional Resources


Configuration Checklist

Before going live:

  • Bot account created and funded ($5+ spent)
  • Steam Mobile Authenticator enabled
  • Shared secret and identity secret extracted
  • API key obtained from Steam
  • Environment variables configured
  • Bot successfully logs in
  • Test trade offer sent and accepted
  • Trade events properly handled
  • Balance credits on acceptance
  • Error handling tested
  • Monitoring set up
  • Backup credentials stored securely

Status: Implementation Ready Next: Configure bot credentials and test login Priority: High - Required for production sell functionality