Complete API documentation for the ORACLE forecasting system.
http://localhost:3000/api
Currently, ORACLE uses server-side OpenRouter API keys configured via environment variables. Client-side authentication is not required for local development.
All API responses follow a consistent format:
{
"success": true,
"data": { ... },
"message": "Optional success message"
}{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": { ... } // Optional additional details
}
}| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Invalid input data |
NOT_FOUND |
404 | Resource not found |
INVALID_OPERATION |
400 | Operation not allowed |
INTERNAL_ERROR |
500 | Server error |
Creates a new forecast record.
POST /api/forecast| Field | Type | Required | Description |
|---|---|---|---|
statusQuo |
string | Yes | Current state description (50-5000 chars) |
resolutionConditions |
string | Yes | How the forecast resolves (20-2000 chars) |
webResearchModel |
string | Yes | Model ID for web research |
reasoningModel |
string | Yes | Model ID for reasoning |
enableBlackSwan |
boolean | No | Enable Layer 4 black swan detection (default: true) |
curl -X POST http://localhost:3000/api/forecast \
-H "Content-Type: application/json" \
-d '{
"statusQuo": "As of December 2024, the Federal Reserve has maintained interest rates at 5.25-5.50% following a series of rate hikes in 2022-2023. Recent inflation data shows CPI at 3.2%, down from peaks of 9.1% in 2022.",
"resolutionConditions": "This question resolves YES if the Federal Reserve announces a rate cut of at least 25 basis points before June 30, 2025. Resolution based on official FOMC announcements.",
"webResearchModel": "perplexity/sonar-reasoning-pro",
"reasoningModel": "google/gemini-3-flash-preview",
"enableBlackSwan": true
}'{
"success": true,
"id": "cm3abc123def456",
"status": "PENDING",
"message": "Forecast created successfully"
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input",
"details": {
"statusQuo": ["Status quo must be at least 50 characters"],
"reasoningModel": ["Invalid reasoning model"]
}
}
}Retrieves a single forecast by ID with all details.
GET /api/forecast/{id}| Parameter | Type | Description |
|---|---|---|
id |
string | Forecast ID |
curl http://localhost:3000/api/forecast/cm3abc123def456{
"success": true,
"data": {
"id": "cm3abc123def456",
"createdAt": "2024-12-18T10:30:00.000Z",
"updatedAt": "2024-12-18T10:35:00.000Z",
"statusQuo": "As of December 2024...",
"resolutionConditions": "This question resolves YES if...",
"webResearchModel": "perplexity/sonar-reasoning-pro",
"reasoningModel": "google/gemini-3-flash-preview",
"enableBlackSwan": true,
"status": "COMPLETED",
"currentLayer": 5,
"errorMessage": null,
"decomposition": { ... },
"swarmEstimates": { ... },
"debateTranscript": { ... },
"blackSwans": { ... },
"calibration": { ... },
"finalDistribution": {
"finalDistribution": {
"pointEstimate": 0.62,
"ci50": [0.55, 0.69],
"ci90": [0.42, 0.78],
"source": "layer5_calibration",
"swarmMean": 0.58,
"swarmMedian": 0.60,
"debateConvergenceScore": 0.85,
"calibrationApplied": true,
"methodologySummary": "..."
}
},
"startedAt": "2024-12-18T10:30:05.000Z",
"completedAt": "2024-12-18T10:35:00.000Z",
"totalTokensUsed": 87500
}
}{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Forecast with ID 'invalid-id' not found"
}
}Retrieves a paginated list of forecasts.
GET /api/forecast| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 10 | Number of results per page (max 100) |
offset |
integer | 0 | Number of results to skip |
status |
string | all | Filter by status: PENDING, RUNNING, COMPLETED, FAILED |
curl "http://localhost:3000/api/forecast?limit=10&offset=0&status=COMPLETED"{
"success": true,
"data": [
{
"id": "cm3abc123def456",
"createdAt": "2024-12-18T10:30:00.000Z",
"statusQuo": "As of December 2024, the Federal Reserve has maintained...",
"status": "COMPLETED",
"currentLayer": 5,
"pointEstimate": 0.62,
"ci90": [0.42, 0.78],
"completedAt": "2024-12-18T10:35:00.000Z"
},
{
"id": "cm3xyz789ghi012",
"createdAt": "2024-12-17T14:00:00.000Z",
"statusQuo": "SpaceX has been developing the Starship rocket...",
"status": "COMPLETED",
"currentLayer": 5,
"pointEstimate": 0.45,
"ci90": [0.28, 0.65],
"completedAt": "2024-12-17T14:08:00.000Z"
}
],
"pagination": {
"total": 25,
"limit": 10,
"offset": 0,
"hasMore": true
}
}Triggers the 5-layer forecasting pipeline for a pending forecast.
POST /api/forecast/{id}/run| Parameter | Type | Description |
|---|---|---|
id |
string | Forecast ID |
curl -X POST http://localhost:3000/api/forecast/cm3abc123def456/run{
"success": true,
"message": "Forecast processing started",
"forecastId": "cm3abc123def456"
}{
"success": false,
"error": {
"code": "INVALID_OPERATION",
"message": "Forecast is already running or completed"
}
}Updates forecast status and layer outputs (used internally by the pipeline).
PATCH /api/forecast/{id}| Parameter | Type | Description |
|---|---|---|
id |
string | Forecast ID |
| Field | Type | Description |
|---|---|---|
status |
string | PENDING, RUNNING, COMPLETED, FAILED |
currentLayer |
integer | Current processing layer (0-5) |
errorMessage |
string | Error message if failed |
decomposition |
object | Layer 1 output |
swarmEstimates |
object | Layer 2 output |
debateTranscript |
object | Layer 3 output |
blackSwans |
object | Layer 4 output |
calibration |
object | Layer 5 output |
finalDistribution |
object | Final probability distribution |
startedAt |
string | ISO timestamp when processing started |
completedAt |
string | ISO timestamp when processing completed |
totalTokensUsed |
integer | Total tokens consumed |
curl -X PATCH http://localhost:3000/api/forecast/cm3abc123def456 \
-H "Content-Type: application/json" \
-d '{
"status": "RUNNING",
"currentLayer": 2
}'{
"success": true,
"data": {
"id": "cm3abc123def456",
"status": "RUNNING",
"currentLayer": 2,
"updatedAt": "2024-12-18T10:31:00.000Z"
}
}Deletes a forecast. Cannot delete forecasts that are currently running.
DELETE /api/forecast/{id}| Parameter | Type | Description |
|---|---|---|
id |
string | Forecast ID |
curl -X DELETE http://localhost:3000/api/forecast/cm3abc123def456{
"success": true,
"message": "Forecast deleted successfully"
}{
"success": false,
"error": {
"code": "INVALID_OPERATION",
"message": "Cannot delete a forecast that is currently running"
}
}Returns all available AI models for web research and reasoning.
GET /api/modelscurl http://localhost:3000/api/models{
"success": true,
"data": {
"webResearchModels": [
{
"id": "perplexity/sonar-reasoning-pro",
"name": "Perplexity Sonar Reasoning Pro",
"description": "Search with reasoning capabilities",
"provider": "Perplexity",
"type": "web_research",
"supportsSystemPrompt": false,
"supportsReasoning": true,
"estimatedLatency": "medium",
"costTier": "high"
},
{
"id": "perplexity/sonar-deep-research",
"name": "Perplexity Sonar Deep Research",
"description": "Deep research with comprehensive web search",
"provider": "Perplexity",
"type": "web_research",
"supportsSystemPrompt": false,
"supportsReasoning": false,
"estimatedLatency": "slow",
"costTier": "high"
}
],
"reasoningModels": [
{
"id": "google/gemini-3-flash-preview",
"name": "Gemini 3 Flash",
"description": "90% of Gemini 3 Pro capability at 4x lower cost",
"provider": "Google",
"type": "reasoning",
"supportsSystemPrompt": true,
"supportsReasoning": true,
"estimatedLatency": "fast",
"costTier": "low"
},
{
"id": "anthropic/claude-opus-4.5",
"name": "Claude Opus 4.5",
"description": "Anthropic's most capable model",
"provider": "Anthropic",
"type": "reasoning",
"supportsSystemPrompt": true,
"supportsReasoning": true,
"estimatedLatency": "medium",
"costTier": "high"
}
],
"defaults": {
"webResearchModel": "perplexity/sonar-reasoning-pro",
"reasoningModel": "google/gemini-3-flash-preview"
}
}
}| Status | Description |
|---|---|
PENDING |
Created but not yet started |
RUNNING |
Currently processing |
COMPLETED |
Successfully completed |
FAILED |
Processing failed |
{
subquestions: Array<{
question: string;
category: "historical" | "current" | "mechanism" | "assumption";
importance: "high" | "medium" | "low";
}>;
referenceClasses: Array<{
name: string;
description: string;
baseRate: number;
relevance: "high" | "medium" | "low";
sampleSize?: number;
sources: string[];
}>;
synthesizedBaseRate: {
estimate: number;
confidence: "high" | "medium" | "low";
reasoning: string;
};
researchFindings: Array<{
query: string;
findings: string;
relevance: "high" | "medium" | "low";
}>;
}{
agents: Array<{
id: string;
name: string;
persona: string;
estimate: number;
confidence: "high" | "medium" | "low";
reasoning: string;
keyFactors: string[];
}>;
aggregateStats: {
mean: number;
median: number;
standardDeviation: number;
range: [number, number];
};
}{
rounds: Array<{
roundNumber: number;
exchanges: Array<{
agentId: string;
position: "for" | "against";
argument: string;
evidence: string[];
rebuttal?: string;
}>;
}>;
convergenceMetrics: {
initialVariance: number;
finalVariance: number;
convergenceScore: number;
convergenceInterpretation: "strong_convergence" | "moderate_convergence" | "no_change" | "divergence";
};
postDebateEstimates: Array<{
agentId: string;
previousEstimate: number;
newEstimate: number;
reasoning: string;
}>;
}{
scenarios: Array<{
id: string;
description: string;
probability: number;
impactMagnitude: number;
impactDirection: "increase" | "decrease" | "invalidate";
category: string;
researchFindings: string;
}>;
integrationRecommendations: {
highImpactScenarios: Array<{ scenarioId: string; adjustment: number }>;
tailDistributionAdjustments: Array<{ direction: string; adjustment: number }>;
};
}{
finalDistribution: {
pointEstimate: number;
ci50: [number, number];
ci90: [number, number];
calibrationApplied: boolean;
extremizationApplied: boolean;
tailIntegrationApplied: boolean;
};
temperatureScaling: {
temperature: number;
adjusted: boolean;
};
extremization: {
extremizationD: number;
applied: boolean;
};
qualityMetrics: {
agentAgreement: number;
calibrationConfidence: "high" | "medium" | "low";
};
betaDistribution: {
alpha: number;
beta: number;
points: Array<{ x: number; y: number }>;
};
percentiles: {
p5: number;
p10: number;
p25: number;
p50: number;
p75: number;
p90: number;
p95: number;
};
methodologySummary: string;
keyFactors: string[];
uncertaintySources: string[];
caveats: string[];
}Real-time progress updates are planned for future releases using WebSocket connections.
Rate limits are determined by your OpenRouter API key tier. The ORACLE application does not impose additional rate limits, but implements:
- Automatic retry with exponential backoff
- Request caching to reduce duplicate API calls
- Configurable concurrency limits
# 1. Create a forecast
FORECAST_ID=$(curl -s -X POST http://localhost:3000/api/forecast \
-H "Content-Type: application/json" \
-d '{
"statusQuo": "Tesla stock (TSLA) is trading at $250 as of December 2024. The company reported Q3 2024 earnings with revenue of $25.5 billion and vehicle deliveries of 462,000 units.",
"resolutionConditions": "Resolves YES if TSLA closes above $300 on any trading day before March 31, 2025. Based on official NASDAQ closing prices.",
"webResearchModel": "perplexity/sonar-reasoning-pro",
"reasoningModel": "google/gemini-3-flash-preview"
}' | jq -r '.id')
echo "Created forecast: $FORECAST_ID"
# 2. Start processing
curl -X POST "http://localhost:3000/api/forecast/$FORECAST_ID/run"
# 3. Poll for completion
while true; do
STATUS=$(curl -s "http://localhost:3000/api/forecast/$FORECAST_ID" | jq -r '.data.status')
LAYER=$(curl -s "http://localhost:3000/api/forecast/$FORECAST_ID" | jq -r '.data.currentLayer')
echo "Status: $STATUS, Layer: $LAYER"
if [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ]; then
break
fi
sleep 10
done
# 4. Get final results
curl -s "http://localhost:3000/api/forecast/$FORECAST_ID" | jq '.data.finalDistribution'import requests
import time
BASE_URL = "http://localhost:3000/api"
def create_forecast(status_quo: str, resolution: str) -> str:
response = requests.post(f"{BASE_URL}/forecast", json={
"statusQuo": status_quo,
"resolutionConditions": resolution,
"webResearchModel": "perplexity/sonar-reasoning-pro",
"reasoningModel": "google/gemini-3-flash-preview",
"enableBlackSwan": True
})
response.raise_for_status()
return response.json()["id"]
def start_forecast(forecast_id: str) -> None:
response = requests.post(f"{BASE_URL}/forecast/{forecast_id}/run")
response.raise_for_status()
def get_forecast(forecast_id: str) -> dict:
response = requests.get(f"{BASE_URL}/forecast/{forecast_id}")
response.raise_for_status()
return response.json()["data"]
def wait_for_completion(forecast_id: str, timeout: int = 600) -> dict:
start = time.time()
while time.time() - start < timeout:
forecast = get_forecast(forecast_id)
if forecast["status"] == "COMPLETED":
return forecast
if forecast["status"] == "FAILED":
raise Exception(f"Forecast failed: {forecast['errorMessage']}")
print(f"Layer {forecast['currentLayer']}/5...")
time.sleep(10)
raise TimeoutError("Forecast timed out")
# Usage
forecast_id = create_forecast(
"The 2024 US presidential election...",
"Resolves YES if Democratic candidate wins..."
)
start_forecast(forecast_id)
result = wait_for_completion(forecast_id)
print(f"Probability: {result['finalDistribution']['finalDistribution']['pointEstimate']:.1%}")