Skip to content

API Reference

dev-mondoshawan edited this page Apr 15, 2026 · 1 revision

API Reference

Complete reference for the Dissensus AI Debate Engine REST API.


Base URL

https://app.dissensus.fun

Authentication

The Dissensus Engine uses a dual authentication model:

Server-Side Keys (Recommended for Production)

Set API keys in the server's .env file:

DEEPSEEK_API_KEY=sk-your-key
OPENAI_API_KEY=sk-your-key
GEMINI_API_KEY=AIza-your-key

When server-side keys are configured, visitors can use the app without providing their own keys.

Client-Side Key Override

Users can provide their own API key via query parameter to use their own quota:

GET /api/debate/stream?topic=...&apiKey=sk-their-key

The client-provided key takes precedence over server-side keys.


Rate Limits

Endpoint Limit Window
POST /api/debate/validate 10 requests 1 minute (prod) / 100 (dev)
GET /api/debate/stream 10 debates 1 minute (prod) / 100 (dev)
POST /api/card 20 requests 1 minute (prod) / 100 (dev)
GET /api/metrics 120 requests 1 minute (prod) / 300 (dev)

Rate limit headers are included in all responses:

  • X-RateLimit-Limit: Maximum requests allowed
  • X-RateLimit-Remaining: Requests remaining in window
  • X-RateLimit-Reset: Unix timestamp when limit resets

Endpoints

GET /api/health

Health check endpoint to verify the service is running.

Response:

{
  "status": "ok",
  "service": "dissensus-engine",
  "providers": "openai, deepseek, gemini"
}

GET /api/config

Returns server configuration including which providers have API keys configured.

Response:

{
  "serverKeys": {
    "openai": true,
    "deepseek": true,
    "gemini": false
  },
  "maxTopicLength": 500
}

GET /api/providers

Returns available AI providers and their models with pricing information.

Response:

{
  "deepseek": {
    "hasServerKey": true,
    "models": [
      {
        "id": "deepseek-chat",
        "name": "DeepSeek V3.2",
        "costPer1kIn": 0.00028,
        "costPer1kOut": 0.00042
      }
    ]
  },
  "openai": {
    "hasServerKey": true,
    "models": [
      {
        "id": "gpt-4o",
        "name": "GPT-4o",
        "costPer1kIn": 0.0025,
        "costPer1kOut": 0.01
      },
      {
        "id": "gpt-4o-mini",
        "name": "GPT-4o Mini",
        "costPer1kIn": 0.00015,
        "costPer1kOut": 0.0006
      }
    ]
  },
  "gemini": {
    "hasServerKey": false,
    "models": [
      {
        "id": "gemini-2.0-flash",
        "name": "Gemini 2.0 Flash",
        "costPer1kIn": 0.0001,
        "costPer1kOut": 0.0004
      },
      {
        "id": "gemini-2.5-flash",
        "name": "Gemini 2.5 Flash",
        "costPer1kIn": 0.0003,
        "costPer1kOut": 0.0025
      }
    ]
  }
}

POST /api/debate/validate

Preflight validation for debate parameters. Use this before initiating an SSE stream to catch errors early.

Request Body:

{
  "topic": "Is Bitcoin a good store of value?",
  "apiKey": "sk-user-key",
  "provider": "deepseek",
  "model": "deepseek-chat"
}

Parameters:

Field Type Required Description
topic string Yes Debate topic (3-500 characters)
apiKey string No User's API key (if not using server key)
provider string No Provider name: deepseek, openai, gemini (default: deepseek)
model string No Model ID (defaults to provider's default)

Success Response (200):

{
  "ok": true
}

Error Response (400):

{
  "error": "Topic must be at least 3 characters"
}
{
  "error": "API key required. Set DEEPSEEK_API_KEY in .env or enter your key."
}

GET /api/debate/stream

Server-Sent Events (SSE) endpoint for live debate streaming. This is the core endpoint that orchestrates the 4-phase dialectical debate.

Query Parameters:

Parameter Type Required Description
topic string Yes Debate topic (3-500 characters)
apiKey string No User's API key (if not using server key)
provider string No Provider: deepseek, openai, gemini
model string No Model ID (defaults per provider)

Example Request:

curl "https://app.dissensus.fun/api/debate/stream?topic=Is%20AI%20safe&provider=deepseek&model=deepseek-chat"

SSE Event Format

The debate stream uses Server-Sent Events. Each event is a JSON object with a type field.

Event Types

debate-start

Sent when the debate begins.

{
  "type": "debate-start",
  "topic": "Is AI safe?",
  "provider": "deepseek",
  "model": "deepseek-chat"
}

phase-start

Sent when a new debate phase begins.

{
  "type": "phase-start",
  "phase": 1,
  "title": "Independent Analysis",
  "description": "Each agent independently analyzes the topic..."
}

Phases:

  1. Independent Analysis - Agents analyze the topic independently
  2. Opening Arguments - Each agent presents their formal position
  3. Cross-Examination - Agents challenge each other's arguments
  4. Final Verdict - PRISM delivers the definitive consensus

agent-start

Sent when an agent begins speaking in a phase.

{
  "type": "agent-start",
  "phase": 1,
  "agent": "cipher"
}

Agents:

  • cipher - The skeptical analyst (red)
  • nova - The optimistic strategist (green)
  • prism - The analytical synthesist (blue)

agent-chunk

Streaming text chunk from an agent's response.

{
  "type": "agent-chunk",
  "phase": 1,
  "agent": "cipher",
  "chunk": "Let me analyze this from a risk perspective..."
}

agent-done

Sent when an agent finishes their response in a phase.

{
  "type": "agent-done",
  "phase": 1,
  "agent": "cipher"
}

phase-done

Sent when a phase completes.

{
  "type": "phase-done",
  "phase": 1
}

debate-done

Sent when the entire debate completes.

{
  "type": "debate-done",
  "topic": "Is AI safe?",
  "verdict": "Full text of PRISM's final verdict..."
}

error

Sent if an error occurs during the debate.

{
  "type": "error",
  "message": "API rate limit exceeded. Please try again in a minute."
}

Stream Termination

The stream ends with:

data: [DONE]


GET /api/debate-of-the-day

Returns a trending topic based on CoinGecko market data. Falls back to a default topic on error.

Response:

{
  "topic": "Is Bitcoin a good store of value?"
}

POST /api/card

Generates a shareable PNG debate card for social media.

Request Body:

{
  "topic": "Is Bitcoin a good store of value?",
  "verdict": "Full verdict text from the debate..."
}

Parameters:

Field Type Required Description
topic string Yes Debate topic (max 200 characters for cards)
verdict string Yes The debate verdict text

Response:

Returns a PNG image with headers:

Content-Type: image/png
Content-Disposition: attachment; filename="dissensus-debate-card.png"
Cache-Control: no-store

If the verdict exceeds 500 characters, the server will automatically summarize it using available AI providers before generating the card.


GET /api/metrics

Returns public usage metrics and recent debate topics.

Query Parameters:

Parameter Type Default Description
recent integer 12 Number of recent topics to return (max 50)

Response:

{
  "totalDebates": 1523,
  "totalErrors": 12,
  "avgResponseTime": 45000,
  "recentTopics": [
    "Is Bitcoin a good store of value?",
    "Will AI replace software engineers?",
    "Is Solana better than Ethereum?"
  ]
}

Error Handling

HTTP Status Codes

Code Meaning
200 Success
400 Bad Request - Invalid parameters
429 Too Many Requests - Rate limit hit
500 Internal Server Error

Common Errors

Missing Topic:

{ "error": "Missing topic" }

Topic Too Short:

{ "error": "Topic must be at least 3 characters" }

Topic Too Long:

{ "error": "Topic must be 500 characters or less" }

Missing API Key:

{ "error": "API key required. Set DEEPSEEK_API_KEY in .env or enter your key." }

Invalid Model:

{ "error": "Invalid model 'gpt-5' for openai. Valid: gpt-4o, gpt-4o-mini" }

JavaScript Client Example

const topic = "Is AI safe?";
const provider = "deepseek";
const model = "deepseek-chat";

const eventSource = new EventSource(
  `/api/debate/stream?topic=${encodeURIComponent(topic)}&provider=${provider}&model=${model}`
);

eventSource.onmessage = (event) => {
  if (event.data === '[DONE]') {
    eventSource.close();
    return;
  }
  
  const data = JSON.parse(event.data);
  
  switch (data.type) {
    case 'phase-start':
      console.log(`Phase ${data.phase}: ${data.title}`);
      break;
    case 'agent-start':
      console.log(`${data.agent} is speaking...`);
      break;
    case 'agent-chunk':
      process.stdout.write(data.chunk); // Stream text
      break;
    case 'agent-done':
      console.log(`\n${data.agent} finished.`);
      break;
    case 'debate-done':
      console.log('Debate complete!');
      console.log(data.verdict);
      break;
    case 'error':
      console.error('Error:', data.message);
      eventSource.close();
      break;
  }
};

eventSource.onerror = (error) => {
  console.error('SSE error:', error);
  eventSource.close();
};

cURL Examples

Health Check:

curl https://app.dissensus.fun/api/health

Validate Debate:

curl -X POST https://app.dissensus.fun/api/debate/validate \
  -H "Content-Type: application/json" \
  -d '{"topic": "Is AI safe?", "provider": "deepseek"}'

Stream Debate:

curl "https://app.dissensus.fun/api/debate/stream?topic=Is%20AI%20safe&provider=deepseek"

Get Metrics:

curl "https://app.dissensus.fun/api/metrics?recent=5"

Generate Card:

curl -X POST https://app.dissensus.fun/api/card \
  -H "Content-Type: application/json" \
  -d '{"topic": "Is AI safe?", "verdict": "AI safety depends on..."}' \
  --output debate-card.png