-
Notifications
You must be signed in to change notification settings - Fork 0
API Reference
Complete reference for the Dissensus AI Debate Engine REST API.
https://app.dissensus.fun
The Dissensus Engine uses a dual authentication model:
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-keyWhen server-side keys are configured, visitors can use the app without providing their own keys.
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.
| 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
Health check endpoint to verify the service is running.
Response:
{
"status": "ok",
"service": "dissensus-engine",
"providers": "openai, deepseek, gemini"
}Returns server configuration including which providers have API keys configured.
Response:
{
"serverKeys": {
"openai": true,
"deepseek": true,
"gemini": false
},
"maxTopicLength": 500
}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
}
]
}
}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."
}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"The debate stream uses Server-Sent Events. Each event is a JSON object with a type field.
Sent when the debate begins.
{
"type": "debate-start",
"topic": "Is AI safe?",
"provider": "deepseek",
"model": "deepseek-chat"
}Sent when a new debate phase begins.
{
"type": "phase-start",
"phase": 1,
"title": "Independent Analysis",
"description": "Each agent independently analyzes the topic..."
}Phases:
- Independent Analysis - Agents analyze the topic independently
- Opening Arguments - Each agent presents their formal position
- Cross-Examination - Agents challenge each other's arguments
- Final Verdict - PRISM delivers the definitive consensus
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)
Streaming text chunk from an agent's response.
{
"type": "agent-chunk",
"phase": 1,
"agent": "cipher",
"chunk": "Let me analyze this from a risk perspective..."
}Sent when an agent finishes their response in a phase.
{
"type": "agent-done",
"phase": 1,
"agent": "cipher"
}Sent when a phase completes.
{
"type": "phase-done",
"phase": 1
}Sent when the entire debate completes.
{
"type": "debate-done",
"topic": "Is AI safe?",
"verdict": "Full text of PRISM's final verdict..."
}Sent if an error occurs during the debate.
{
"type": "error",
"message": "API rate limit exceeded. Please try again in a minute."
}The stream ends with:
data: [DONE]
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?"
}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.
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?"
]
}| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid parameters |
| 429 | Too Many Requests - Rate limit hit |
| 500 | Internal Server Error |
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" }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();
};Health Check:
curl https://app.dissensus.fun/api/healthValidate 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