API Documentation

Study Buddy’s backend API provides endpoints for AI chat interactions, search functionality, and configuration management. All APIs are built using Next.js API routes.

Base URL

http://localhost:3000/api  (Development)
file://app.asar/api        (Production Electron)

Authentication

No authentication is required as Study Buddy runs locally. API keys for external services are managed through the settings system.

API Endpoints

Chat API

POST /api/getChat

Initiate a streaming chat conversation with the configured AI provider.

Request Body:

{
  messages: {
    role: "user" | "assistant" | "system";
    content: string;
  }[]
}

Headers:

Content-Type: application/json
X-StudyBuddy-Settings: string (optional, JSON-encoded settings)

Response:

  • Content-Type: text/event-stream
  • Status: 200 (success), 500 (error)

Streaming Response Format:

data: {"type": "chunk", "content": "Partial response text"}

data: {"type": "chunk", "content": " continuation..."}

data: {"type": "done"}

Error Response:

{
  error: string;
  details?: string;
}

Example:

const response = await fetch('/api/getChat', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    messages: [
      { role: 'user', content: 'Explain photosynthesis' }
    ]
  })
});

// Handle streaming response
const reader = response.body?.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  const chunk = decoder.decode(value);
  // Process chunk...
}

Search API

POST /api/getSources

Search for relevant information sources based on a query.

Request Body:

{
  question: string;
}

Headers:

Content-Type: application/json
X-StudyBuddy-Settings: string (optional, JSON-encoded settings)

Response:

{
  sources: {
    name: string;    // Page title or description
    url: string;     // Source URL
  }[]
}

Error Response:

{
  error: string;
  details?: string;
}

Search Engine Support:

Engine Type API Key Required Features
bing Commercial API Yes High-quality results, fast
serper Google API proxy Yes Google results, reliable
searxng Self-hosted No Privacy-focused, customizable
duckduckgo Web scraping No Privacy-focused, free
brave Independent API Yes Ad-free results, privacy
disabled None No Disables search functionality

Example:

const response = await fetch('/api/getSources', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    question: 'renewable energy sources'
  })
});

const data = await response.json();
console.log(data.sources); // Array of search results

POST /api/getParsedSources

Parse and extract content from provided source URLs.

Request Body:

{
  sources: {
    name: string;
    url: string;
  }[]
}

Response:

{
  sources: {
    name: string;
    url: string;
    fullContent: string;  // Extracted text content
  }[]
}

Settings API

GET /api/settings

Retrieve current application settings (API keys are redacted for security).

Response:

{
  llmProvider: "openai" | "together" | "custom";
  llmApiKey: "";        // Always empty for security
  llmBaseUrl: string;
  llmModel: string;
  searchEngine: "bing" | "serper" | "searxng" | "duckduckgo" | "brave" | "disabled";
  searchApiKey: "";     // Always empty for security
  searchUrl: string;
  defaultEducationLevel: string;
}

POST /api/settings

Update application settings.

Request Body:

{
  llmProvider?: "openai" | "together" | "custom";
  llmApiKey?: string;
  llmBaseUrl?: string;
  llmModel?: string;
  searchEngine?: "bing" | "serper" | "searxng" | "duckduckgo" | "brave" | "disabled";
  searchApiKey?: string;
  searchUrl?: string;
  defaultEducationLevel?: string;
}

Response:

{
  success: boolean;
  message: string;
}

Error Handling

Standard Error Format

All API endpoints return errors in a consistent format:

{
  error: string;           // Human-readable error message
  details?: string;        // Additional error details
  code?: number;          // Optional error code
}

Common HTTP Status Codes

  • 200: Success
  • 400: Bad Request (invalid input)
  • 500: Internal Server Error
  • 429: Too Many Requests (rate limiting)

Error Examples

Invalid Request:

{
  "error": "Invalid request format",
  "details": "Messages array is required"
}

Service Unavailable:

{
  "error": "AI service unavailable",
  "details": "OpenAI API returned 503 status"
}

Configuration Error:

{
  "error": "API key required",
  "details": "OpenAI API key not configured in settings"
}

Rate Limiting

Search APIs

  • SearXNG: 2-second delay between requests to same server
  • DuckDuckGo: Built-in delays to prevent blocking
  • Commercial APIs: Respect provider rate limits

AI APIs

  • OpenAI: Follows OpenAI rate limits
  • Together AI: Follows Together AI rate limits
  • Custom: No built-in limits (configure at provider level)

Configuration Headers

X-StudyBuddy-Settings

Some endpoints accept runtime settings via the X-StudyBuddy-Settings header:

const settings = JSON.stringify({
  llmProvider: 'openai',
  llmApiKey: 'sk-...',
  searchEngine: 'duckduckgo'
});

fetch('/api/getChat', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-StudyBuddy-Settings': settings
  },
  body: JSON.stringify({ messages })
});

This allows frontend components to override server-side settings temporarily.

Request/Response Examples

Complete Chat Flow

// 1. Search for sources
const sourcesRes = await fetch('/api/getSources', {
  method: 'POST',
  body: JSON.stringify({ question: 'quantum physics basics' })
});
const { sources } = await sourcesRes.json();

// 2. Parse source content
const parsedRes = await fetch('/api/getParsedSources', {
  method: 'POST', 
  body: JSON.stringify({ sources })
});
const { sources: parsedSources } = await parsedRes.json();

// 3. Start AI chat with context
const chatRes = await fetch('/api/getChat', {
  method: 'POST',
  body: JSON.stringify({
    messages: [
      {
        role: 'system',
        content: `Context: ${parsedSources.map(s => s.fullContent).join('\n')}`
      },
      {
        role: 'user', 
        content: 'Explain quantum physics at a high school level'
      }
    ]
  })
});

// 4. Handle streaming response
const reader = chatRes.body.getReader();
// ... process stream

Settings Management

// Get current settings
const currentSettings = await fetch('/api/settings').then(r => r.json());

// Update provider
await fetch('/api/settings', {
  method: 'POST',
  body: JSON.stringify({
    llmProvider: 'together',
    llmApiKey: 'your-api-key',
    llmModel: 'meta-llama/Llama-3.1-8B-Instruct-Turbo'
  })
});

WebSocket Alternative

While Study Buddy uses Server-Sent Events (SSE) for streaming, you could implement WebSocket support:

// Hypothetical WebSocket implementation
const ws = new WebSocket('ws://localhost:3000/api/chat-ws');

ws.send(JSON.stringify({
  type: 'chat',
  messages: [{ role: 'user', content: 'Hello' }]
}));

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === 'chunk') {
    // Handle streaming chunk
  }
};

For implementation details and source code, see the GitHub repository.