Files
RedditBot/docs/api.md
T

16 KiB

API Reference

Complete reference for the RedditBot web dashboard API.


Table of Contents

  1. Overview
  2. Authentication
  3. Base URL
  4. Bot Status & Control
  5. Activity & Messages
  6. Chat & Conversations
  7. Media
  8. Analytics
  9. Configuration
  10. Logs & Debugging
  11. Error Responses
  12. SSE Events

Overview

The RedditBot web dashboard exposes a REST API for monitoring and controlling the bot. All endpoints are served by the Express server.

Content-Type: application/json (except SSE)
Response Format: JSON
Authentication: Required for cutover; not yet enforced by the checked-in Express host


Authentication

The React cutover requires a single Express authentication boundary covering the dashboard assets, /api, both SSE streams, debug routes, and private media. That boundary and its token/session configuration are not present in the checked-in server yet. Until they land and their security tests pass, bind the dashboard to a trusted network and do not expose port 3000 publicly.

The intended contract is an HttpOnly, SameSite=Strict dashboard session for interactive users and bearer-token access for API clients. Treat those details as a migration requirement, not as proof of current protection.


Base URL

http://localhost:3000/api

The port is configured via config.web.port (default: 3000).


Bot Status & Control

Get Bot Statistics

Retrieve current bot statistics including running state, counts, and response rate.

GET /api/stats

Response:

{
  "running": true,
  "processed": 1250,
  "sent": 980,
  "responded": 312,
  "responseRate": 0.318,
  "hourlyCount": 15,
  "timeUntilSlot": 45
}

Fields:

Field Type Description
running boolean Whether the bot is currently running
processed number Total posts processed
sent number Total messages sent
responded number Total messages that received responses
responseRate number Response rate (0.0 to 1.0)
hourlyCount number Messages sent this hour
timeUntilSlot number Seconds until next message slot

Start Bot

Start the bot's main processing loop.

POST /api/start

Response:

{
  "success": true,
  "message": "Bot started"
}

Errors:

{
  "error": "Bot is already running"
}

Stop Bot

Stop the bot's main processing loop gracefully.

POST /api/stop

Response:

{
  "success": true,
  "message": "Bot stopping..."
}

Activity & Messages

Get Activity Log

Retrieve recent activity entries from the bot's log.

GET /api/activity

Query Parameters:

Parameter Type Default Description
limit number 50 Number of entries to return

Response:

[
  {
    "level": "info",
    "message": "Processed post abc123 from r/gonewild",
    "timestamp": "2024-01-15T10:30:00.000Z"
  },
  {
    "level": "warn",
    "message": "AI model refused to analyze post def456",
    "timestamp": "2024-01-15T10:28:00.000Z"
  },
  {
    "level": "error",
    "message": "Failed to send DM to user789: timeout",
    "timestamp": "2024-01-15T10:25:00.000Z"
  }
]

Get Posts by Author

Look up processed posts for a specific Reddit user.

GET /api/posts/by-author/:username

Path Parameters:

Parameter Type Description
username string Reddit username

Response:

[
  {
    "id": "abc123",
    "subreddit": "gonewild",
    "author": "user123",
    "title": "Summer vibes",
    "image_url": "https://...",
    "image_analysis": "{\"gender\":\"F\",\"description\":\"...\"}",
    "generated_message": "Hey, you look amazing...",
    "processed_at": 1716234567,
    "message_sent": 1,
    "error": null
  }
]

Get Sent Messages

Retrieve recent sent messages.

GET /api/messages

Query Parameters:

Parameter Type Default Description
limit number 50 Number of messages to return

Response:

[
  {
    "id": 1,
    "post_id": "abc123",
    "recipient": "user123",
    "subject": "Stunning",
    "message": "Hey, you look amazing...",
    "sent_at": "2024-01-15T10:30:00.000Z",
    "strategy_id": "compliment",
    "got_response": 1,
    "response_checked_at": "2024-01-15T11:00:00.000Z"
  }
]

Get Successful Messages

Retrieve successful message/response pairs used for few-shot learning.

GET /api/successful

Query Parameters:

Parameter Type Default Description
limit number 50 Number of entries to return

Response:

[
  {
    "id": 1,
    "sent_message_id": 1,
    "original_message": "Hey, you look amazing...",
    "image_analysis": "{\"gender\":\"F\",\"description\":\"...\"}",
    "post_title": "Summer vibes",
    "response_snippet": "Thank you so much! 😊",
    "subreddit": "gonewild",
    "created_at": "2024-01-15T10:30:00.000Z"
  }
]

Chat & Conversations

Get Active Chats

Retrieve cached active conversations.

GET /api/chats

Response:

[
  {
    "chatId": "chat_abc123",
    "participant": "user456",
    "lastMessage": "Thanks for the compliment!",
    "timestamp": "2024-01-15T10:30:00.000Z",
    "hasNewMessages": false
  }
]

Fetch All Chats

Force-fetch all chats from Reddit (refreshes cache).

POST /api/chats/fetch-all

Response:

{
  "success": true,
  "count": 15
}

Get Conversations

Retrieve all cached conversations.

GET /api/conversations

Response:

[
  {
    "chatId": "chat_abc123",
    "participants": ["user456", "bot"],
    "messageCount": 24,
    "lastUpdated": "2024-01-15T10:30:00.000Z",
    "hasNewMessages": false,
    "pendingReply": false,
    "isUpsell": false
  }
]

Get Conversation Detail

Retrieve full details of a specific conversation.

GET /api/conversations/:id

Path Parameters:

Parameter Type Description
id string Chat ID

Response:

{
  "chatId": "chat_abc123",
  "participants": ["user456", "bot"],
  "messages": [
    {
      "author": "user456",
      "text": "Hey there!",
      "timestamp": "2024-01-15T10:00:00.000Z"
    },
    {
      "author": "bot",
      "text": "Hi! Thanks for the compliment!",
      "timestamp": "2024-01-15T10:01:00.000Z"
    },
    {
      "author": "user456",
      "text": "Thanks for the compliment!",
      "timestamp": "2024-01-15T10:02:00.000Z"
    }
  ],
  "lastUpdated": "2024-01-15T10:30:00.000Z",
  "hasNewMessages": false,
  "pendingReply": false,
  "isUpsell": false
}

Suggest Reply

Generate an AI reply suggestion for a conversation.

POST /api/conversations/:id/suggest-reply

Path Parameters:

Parameter Type Description
id string Chat ID

Response:

{
  "success": true,
  "reply": "Thanks for reaching out! 😊 How's your day going?"
}

Send Reply

Send a manual reply in a conversation.

POST /api/conversations/:id/send-reply

Path Parameters:

Parameter Type Description
id string Chat ID

Request Body:

{
  "text": "Thanks for reaching out! 😊"
}

Response:

{
  "success": true,
  "delivered": true
}

Approve Pending Reply

Approve an auto-reply that is pending manual approval.

POST /api/conversations/:id/approve-reply

Path Parameters:

Parameter Type Description
id string Chat ID

Response:

{
  "success": true,
  "message": "Reply sent"
}

Reject Pending Reply

Reject an auto-reply that is pending manual approval.

POST /api/conversations/:id/reject-reply

Path Parameters:

Parameter Type Description
id string Chat ID

Response:

{
  "success": true,
  "message": "Reply rejected"
}

Dismiss Upsell Flag

Clear the upsell/spam flag on a conversation.

POST /api/conversations/:id/dismiss-upsell

Path Parameters:

Parameter Type Description
id string Chat ID

Response:

{
  "success": true,
  "message": "Upsell flag dismissed"
}

Media

Retrieve downloaded media files.

GET /api/media

Query Parameters:

Parameter Type Default Description
limit number 100 Number of files to return

Response:

[
  {
    "hash": "abc123def456",
    "filename": "abc123def456.jpg",
    "size": 245678,
    "conversationId": "chat_abc123",
    "downloadedAt": "2024-01-15T10:30:00.000Z"
  }
]

Get Media Sync Status

Retrieve current media sync status.

GET /api/media/sync

Response:

{
  "running": false,
  "mode": null,
  "progress": 0,
  "total": 0,
  "completed": 0,
  "lastSync": "2024-01-15T09:00:00.000Z"
}

Trigger Incremental Sync

Start an incremental media sync (top 10 conversations).

POST /api/media/sync

Response:

{
  "success": true,
  "message": "Incremental sync started"
}

Trigger Full Sync

Start a full media sync (all conversations).

POST /api/media/sync/full

Response:

{
  "success": true,
  "message": "Full sync started"
}

Analytics

Response Rate by Subreddit

Get response rates broken down by subreddit.

GET /api/analytics/by-subreddit

Response:

[
  {
    "subreddit": "gonewild",
    "sent": 500,
    "responded": 175,
    "rate": 0.35
  },
  {
    "subreddit": "ratemyboobs",
    "sent": 300,
    "responded": 90,
    "rate": 0.30
  },
  {
    "subreddit": "HomemadeNsfw",
    "sent": 180,
    "responded": 72,
    "rate": 0.40
  }
]

Response Rate by Strategy

Get response rates broken down by A/B test variant.

GET /api/analytics/by-strategy

Response:

[
  {
    "strategy_id": "compliment",
    "sent": 400,
    "responded": 140,
    "rate": 0.35
  },
  {
    "strategy_id": "question",
    "sent": 350,
    "responded": 147,
    "rate": 0.42
  },
  {
    "strategy_id": "observation",
    "sent": 230,
    "responded": 69,
    "rate": 0.30
  }
]

Daily Response Trend

Get daily response rates over time.

GET /api/analytics/trend

Response:

[
  {
    "date": "2024-01-01",
    "sent": 18,
    "responded": 6,
    "rate": 0.33
  },
  {
    "date": "2024-01-02",
    "sent": 22,
    "responded": 8,
    "rate": 0.36
  },
  {
    "date": "2024-01-03",
    "sent": 15,
    "responded": 4,
    "rate": 0.27
  }
]

Configuration

Get Runtime Configuration

Get current runtime configuration.

GET /api/config

Response:

{
  "reddit": {
    "subreddits": ["gonewild", "ratemyboobs"],
    "pollInterval": 15,
    "targetGender": "F",
    "sellerKeywords": ["seller", "onlyfans"]
  },
  "openrouter": {
    "model": "meta-llama/llama-3.2-90b-vision-preview",
    "fallbackModels": ["google/gemini-2.0-flash-001"]
  },
  "rateLimit": {
    "minDelayMs": 30000,
    "maxMessagesPerHour": 20,
    "jitterMs": 15000
  },
  "browser": {
    "headless": true,
    "userDataDir": "./data/browser"
  },
  "database": {
    "path": "./data/reddit-bot.db"
  },
  "mediaSync": {
    "enabled": true,
    "intervalMinutes": 30
  },
  "autoReply": {
    "enabled": true,
    "autoSend": false,
    "checkInterval": 10
  },
  "strategyVariants": [
    {
      "name": "compliment",
      "enabled": true
    }
  ],
  "web": {
    "port": 3000
  },
  "dryRun": false,
  "fewShotExamples": 3,
  "minStrategySamples": 10,
  "explorationRate": 0.15
}

Update Runtime Configuration

Update runtime configuration values without restarting.

PUT /api/config

Request Body (partial updates supported):

{
  "rateLimit": {
    "minDelayMs": 45000,
    "maxMessagesPerHour": 15
  },
  "dryRun": true,
  "reddit": {
    "pollInterval": 20
  }
}

Response:

{
  "success": true,
  "config": { ... }
}

Errors:

{
  "error": "Invalid config: rateLimit.minDelayMs must be a positive integer"
}

Logs & Debugging

SSE Log Stream

Connect to the realtime log stream via Server-Sent Events.

GET /api/logs/stream

Headers:

Header Value
Accept text/event-stream

Response (streaming):

event: log
data: {"level":"info","message":"Bot started","timestamp":"2024-01-15T10:30:00.000Z"}

event: log
data: {"level":"info","message":"Processed post abc123","timestamp":"2024-01-15T10:30:05.000Z"}

event: log
data: {"level":"warn","message":"AI refusal detected","timestamp":"2024-01-15T10:30:10.000Z"}

Client usage (JavaScript):

const eventSource = new EventSource('/api/logs/stream');

eventSource.onmessage = (event) => {
  const log = JSON.parse(event.data);
  console.log(log.level, log.message);
};

// Close connection
eventSource.close();

Get Recent Logs

Retrieve recent log entries via HTTP (non-streaming).

GET /api/logs

Query Parameters:

Parameter Type Default Description
limit number 100 Number of entries to return
level string all Filter by level: info, warn, error

Response: Same format as /api/activity.


Get Rate Limiter Timers

Get current rate limiter status.

GET /api/timers

Response:

{
  "timeUntilSlot": 45,
  "hourlyCount": 15,
  "maxMessagesPerHour": 20,
  "isThrottled": false
}

Debug: Inspect DOM

Inspect the current chat DOM structure (for debugging shadow DOM issues).

POST /api/debug/inspect-dom

Response:

{
  "success": true,
  "domStructure": { ... }
}

Debug: Manual Response Check

Trigger a manual response check (bypasses scheduled interval).

POST /api/debug/check-responses

Response:

{
  "success": true,
  "responsesFound": 3,
  "updated": 2
}

Error Responses

All error responses follow this format:

{
  "error": "Error message describing what went wrong"
}

Common Error Codes

HTTP Status Description Example
400 Bad Request Invalid query parameter
404 Not Found Resource not found
500 Internal Server Error Unexpected error

SSE Events

GET /api/events/stream is the typed resumable event stream used by the React dashboard. Each SSE frame contains id, event, and data fields. The data is the complete validated event envelope:

{
  "id": "1786201200000-000000",
  "occurredAt": "2026-08-08T15:00:00.000Z",
  "type": "log.created",
  "payload": {
    "level": "info",
    "message": "Dashboard started"
  }
}

Clients may reconnect with Last-Event-ID; the server replays retained events after that ID in order. The stream sends heartbeats, bounds buffered events and slow-client queues. Applying the same authentication boundary as the API is a pending cutover gate.

Current event families include bot status, message sent or failed, conversation updated, reply received, sync lifecycle and progress, rate-limit state, Reddit session state, and logs.

GET /api/logs/stream remains temporarily available for the legacy dashboard. Its untyped connected, log, and sync-progress frames should not be used by new clients.

Log Levels:

Level Description
info Normal operation
warn Warning (recoverable issue)
error Error (action failed)
debug Debug information