Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Metaculus/metaculus/llms.txt

Use this file to discover all available pages before exploring further.

This guide shows you how to submit forecasts for different question types using the Metaculus API.

Prerequisites

All API requests require authentication. Make sure you have:
  1. Generated an API token from your account settings
  2. Include the token in the Authorization header: Token YOUR_API_TOKEN

Binary Questions

Binary questions have yes/no outcomes. Submit a probability between 0 and 1.
1

Get the question details

First, retrieve the question to get its ID and confirm it’s a binary question:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Get post details
post_id = 1
response = requests.get(
    f"https://www.metaculus.com/api/posts/{post_id}/",
    headers=headers
)
post_data = response.json()
question = post_data["question"]

print(f"Question ID: {question['id']}")
print(f"Type: {question['type']}")
print(f"Title: {question['title']}")
2

Submit your binary forecast

Submit a probability for the yes outcome:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit binary forecast
forecast_data = [
    {
        "question": 1,  # Question ID
        "probability_yes": 0.63
    }
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("Forecast submitted successfully!")
else:
    print(f"Error: {response.status_code}")
    print(response.json())

Numeric Questions (Continuous)

Numeric questions require a 201-point CDF (Cumulative Distribution Function). For detailed guidance on generating CDFs, see the Continuous CDF Guide.
1

Get the question scaling

Retrieve the question details to understand its range and scaling:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Get question details
post_id = 3530
response = requests.get(
    f"https://www.metaculus.com/api/posts/{post_id}/",
    headers=headers
)
question = response.json()["question"]

print(f"Type: {question['type']}")
print(f"Range: {question['scaling']['range_min']} to {question['scaling']['range_max']}")
print(f"Unit: {question['unit']}")
print(f"Open lower bound: {question['open_lower_bound']}")
print(f"Open upper bound: {question['open_upper_bound']}")
2

Generate a CDF

Create a 201-point CDF. This example shows a simple approach:
Python
import numpy as np

# For a question with closed bounds (range_min to range_max)
# Generate a simple normal-like distribution
def simple_cdf(mean_location=0.5, spread=0.3):
    """
    Generate a 201-point CDF.
    mean_location: center of distribution (0 to 1)
    spread: how spread out the distribution is
    """
    points = np.linspace(0, 1, 201)
    # Simple sigmoid-based CDF
    cdf = 1 / (1 + np.exp(-(points - mean_location) / spread))
    # Normalize to [0, 1]
    cdf = (cdf - cdf.min()) / (cdf.max() - cdf.min())
    return cdf.tolist()

my_cdf = simple_cdf(mean_location=0.6, spread=0.15)
print(f"CDF has {len(my_cdf)} points")
print(f"First value: {my_cdf[0]:.5f}, Last value: {my_cdf[-1]:.5f}")
For production use, see the Continuous CDF Guide for proper CDF generation that handles:
  • Linear and logarithmic scaling
  • Open and closed bounds
  • Percentile-based distributions
  • CDF standardization and validation
3

Submit your numeric forecast

Submit the CDF to the API:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit continuous forecast
forecast_data = [
    {
        "question": 3530,
        "continuous_cdf": my_cdf  # 201-point list
    }
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("Forecast submitted successfully!")
else:
    print(f"Error: {response.status_code}")
    print(response.json())

Multiple Choice Questions

For multiple choice questions, provide probabilities for each option that sum to 1.0.
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit multiple choice forecast
forecast_data = [
    {
        "question": 20772,
        "probability_yes_per_category": {
            "Democratic": 0.45,
            "Republican": 0.40,
            "Libertarian": 0.08,
            "Green": 0.05,
            "Other": 0.02
        }
    }
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("Forecast submitted successfully!")
The probabilities must sum to exactly 1.0, or the API will reject your forecast.

Group of Questions

For posts containing multiple sub-questions, submit forecasts for each one:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit forecasts for multiple questions in a group
forecast_data = [
    {"question": 10880, "probability_yes": 0.11},  # 2030
    {"question": 10923, "probability_yes": 0.22},  # 2035
    {"question": 10924, "probability_yes": 0.33}   # 2040
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("All forecasts submitted successfully!")

Withdrawing Forecasts

You can withdraw your current forecast on a question:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Withdraw forecast
withdrawal_data = [
    {"question": 1}
]

response = requests.post(
    "https://www.metaculus.com/api/questions/withdraw/",
    headers=headers,
    json=withdrawal_data
)

if response.status_code == 201:
    print("Forecast withdrawn successfully!")

Next Steps