← Back to Metaculus docs

Metaculus — Tool Reference

Browse Metaculus community forecasts, submit and withdraw predictions, and track your own forecasting record

9 tools · auto-generated from the deployed toolkit

Your AI assistant discovers and invokes these tools through the MCP Server's meta tools — it calls execute_tool with the tool name and arguments below.

# download_question_data read

Download a Metaculus question's CSV export (question, forecast, score and comment data) — a restricted endpoint that returns an access hint when refused.

Full description
Download the CSV-zip export for a post, question or project.

Supply at least one of `post_id`, `question_id` or `project_id`
(`project_id` only works if your account is whitelisted for that project).
This is the richest source of calibration history — full forecast series and
per-user scores rather than a single aggregate snapshot.

**The endpoint is restricted.** Without approval Metaculus answers 401/403,
and this tool returns `status="access_denied"` with an `access_hint` and the
application link instead of raising — every other failure (404, 429, 5xx,
transport) still raises.

Caps, applied in this order: the zip is streamed under BOTH an 8 MB ceiling
and this invocation's remaining time budget — exceeding either abandons the
download and returns `status="too_large"` or `status="timed_out"` with no
files, and Metaculus's asynchronous /api/data/email/ export (which this
toolkit does not wrap) is the route for those. Reading the archive is a
SECOND bounded phase with its own share of the remaining budget, so an
export that downloads but cannot be opened in time is reported as such
rather than running the invocation into its ceiling. Then at most 1000
archive members are listed (`members_total` and `members_truncated` say when
there were more), each CSV is read up to 20000 characters, and the whole
response stops adding text at 40000 characters. Files past the TEXT budgets
are still LISTED with their sizes, just with `text=null`; members past the
1000-member cap are not listed at all, only counted. Set
`include_file_text=false` for the listing only.
Parameter Type Required Description
post_id integer | null No
question_id integer | null No
project_id integer | null No Only accepted when your account is whitelisted for that project.
sub_question integer | null No Restrict a group/conditional export to one subquestion.
aggregation_methods string | null No Comma-separated subset of recency_weighted, unweighted, metaculus_prediction, single_aggregation — or 'all'. Omit for recency_weighted only; supplying it triggers a recalculation upstream.
include_comments boolean | null No
include_scores boolean | null No
include_key_factors boolean | null No
include_file_text boolean No Return CSV text, not just the file listing. Default: true
Parameter schema (JSON)
{
  "properties": {
    "post_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Post Id"
    },
    "question_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Question Id"
    },
    "project_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only accepted when your account is whitelisted for that project.",
      "title": "Project Id"
    },
    "sub_question": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Restrict a group/conditional export to one subquestion.",
      "title": "Sub Question"
    },
    "aggregation_methods": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Comma-separated subset of recency_weighted, unweighted, metaculus_prediction, single_aggregation — or 'all'. Omit for recency_weighted only; supplying it triggers a recalculation upstream.",
      "title": "Aggregation Methods"
    },
    "include_comments": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Include Comments"
    },
    "include_scores": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Include Scores"
    },
    "include_key_factors": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Include Key Factors"
    },
    "include_file_text": {
      "default": true,
      "description": "Return CSV text, not just the file listing.",
      "title": "Include File Text",
      "type": "boolean"
    }
  },
  "title": "DownloadQuestionDataParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "AccessHint": {
      "description": "Machine-readable note that a response was shortened by access tier.",
      "properties": {
        "code": {
          "description": "tier_gated (data withheld for this token) or restricted_endpoint (the endpoint itself needs approval).",
          "title": "Code",
          "type": "string"
        },
        "message": {
          "description": "Human-readable explanation of what is missing.",
          "title": "Message",
          "type": "string"
        },
        "data_needs_form_url": {
          "default": "https://docs.google.com/forms/d/e/1FAIpQLSeJhtZzHl5qMvBjbXbatyaqoS4IU7RE0GGw_vlhs6I9syqn1g/viewform?usp=pp_url&entry.192763438=https://www.metaculus.com/api/",
          "description": "Metaculus Data Needs form — the free Bot Benchmarking tier and bespoke grants are both requested here.",
          "title": "Data Needs Form Url",
          "type": "string"
        },
        "contact_email": {
          "default": "api-requests@metaculus.com",
          "description": "Metaculus API contact address.",
          "title": "Contact Email",
          "type": "string"
        },
        "unlock_note": {
          "default": "Submitting a forecast on a question permanently unlocks that question's text and resolution for your account, so access widens as you forecast.",
          "description": "How access grows without an upgrade.",
          "title": "Unlock Note",
          "type": "string"
        }
      },
      "required": [
        "code",
        "message"
      ],
      "title": "AccessHint",
      "type": "object"
    },
    "ZipMember": {
      "properties": {
        "name": {
          "title": "Name",
          "type": "string"
        },
        "compressed_bytes": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Compressed Bytes"
        },
        "uncompressed_bytes": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Size declared by the archive, not measured.",
          "title": "Uncompressed Bytes"
        },
        "text": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "CSV text, present only when include_file_text was true and the per-file / total character budget still had room.",
          "title": "Text"
        },
        "text_truncated": {
          "default": false,
          "title": "Text Truncated",
          "type": "boolean"
        }
      },
      "required": [
        "name"
      ],
      "title": "ZipMember",
      "type": "object"
    }
  },
  "properties": {
    "status": {
      "description": "ok, access_denied, too_large, timed_out, or empty. `timed_out` means the download or the archive read stopped ITSELF because this invocation ran out of time — nothing is still in flight, and no forecast or comment was written either way, so retrying is safe. A download abandoned in a way this side could not stop raises instead of returning, so it can say so.",
      "title": "Status",
      "type": "string"
    },
    "http_status": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Http Status"
    },
    "requested": {
      "additionalProperties": true,
      "title": "Requested",
      "type": "object"
    },
    "zip_bytes": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Zip Bytes"
    },
    "files": {
      "description": "The archive's members, capped at 1000. When the archive holds more, `members_truncated` is true and `members_total` says how many there were; the ones past the cap are neither listed nor read.",
      "items": {
        "$ref": "#/$defs/ZipMember"
      },
      "title": "Files",
      "type": "array"
    },
    "members_total": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "How many members the archive's central directory declared — which can exceed len(files). Null unless the archive was opened, i.e. on every status other than `ok`.",
      "title": "Members Total"
    },
    "members_truncated": {
      "default": false,
      "description": "True when the archive held more than the 1000 members `files` lists. Independent of `text_truncated` on a member, which is about one file's text rather than about the list.",
      "title": "Members Truncated",
      "type": "boolean"
    },
    "total_text_chars": {
      "default": 0,
      "title": "Total Text Chars",
      "type": "integer"
    },
    "notes": {
      "items": {
        "type": "string"
      },
      "title": "Notes",
      "type": "array"
    },
    "access_hint": {
      "anyOf": [
        {
          "$ref": "#/$defs/AccessHint"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    }
  },
  "required": [
    "status",
    "requested"
  ],
  "title": "DownloadDataResult",
  "type": "object"
}

# get_access_status read

Probe what your Metaculus token can actually see: how much Community Prediction data comes back, and whether bulk export works.

Full description
Measure this token's real data access.

Metaculus exposes NO endpoint that reports your access tier, so this probes
empirically: it samples open posts and resolved posts with the Community
Prediction requested, counts how many came back with one, and asks
/api/data/download/ for a single post to see whether bulk CSV export is
permitted (the export body is never downloaded — only its status).

`tier_suggestion` is a Toolforest-side LABEL over those counts, not a
Metaculus fact: `no_cp_in_sample` when nothing carried a CP,
`base_tier_likely` under 25% coverage, `expanded_tier_likely` at or above it.
`tier_suggestion_basis` spells out the arithmetic. Nothing in this toolkit
gates a request on this label.

The counts describe THE SAMPLE — the default feed ordering for each status —
not the whole site, and CP coverage is question-specific, so a different
sample can give a different fraction. Re-run it after an access upgrade to
confirm the change landed.

This tool makes up to four sequential requests, and EVERY one of them —
including the first sample — is admitted only if enough of the invocation's
time budget is left to start it. A phase that is not admitted is SKIPPED
rather than run into the Lambda ceiling, and rather than raised: nothing was
sent, so the tool still returns whatever the earlier phases learned.

A skipped phase is never dressed up as evidence. Its sample count stays 0
but its status field says `insufficient_budget`, so `open_sampled = 0` means
"not sampled" there and "sampled and empty" under `sampled` — the two are
never conflated. When NO sample ran, `tier_suggestion` is
`insufficient_budget` rather than `no_cp_in_sample`, and no tier hint is
emitted, because an unsampled feed is evidence of nothing. When the samples
ran but the feeds returned no posts at all, the label is
`no_posts_in_sample` for the same reason. `notes` names every skipped phase,
and the export probe reports `attempted=false`.
Parameter Type Required Description
sample_size integer No Posts to sample per status (open and resolved are sampled separately). Default: 40
probe_post_id integer | null No Post id for the /api/data/download/ probe. Defaults to the first post in the open sample.
Parameter schema (JSON)
{
  "properties": {
    "sample_size": {
      "default": 40,
      "description": "Posts to sample per status (open and resolved are sampled separately).",
      "maximum": 100,
      "minimum": 1,
      "title": "Sample Size",
      "type": "integer"
    },
    "probe_post_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Post id for the /api/data/download/ probe. Defaults to the first post in the open sample.",
      "title": "Probe Post Id"
    }
  },
  "title": "GetAccessStatusParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "AccessHint": {
      "description": "Machine-readable note that a response was shortened by access tier.",
      "properties": {
        "code": {
          "description": "tier_gated (data withheld for this token) or restricted_endpoint (the endpoint itself needs approval).",
          "title": "Code",
          "type": "string"
        },
        "message": {
          "description": "Human-readable explanation of what is missing.",
          "title": "Message",
          "type": "string"
        },
        "data_needs_form_url": {
          "default": "https://docs.google.com/forms/d/e/1FAIpQLSeJhtZzHl5qMvBjbXbatyaqoS4IU7RE0GGw_vlhs6I9syqn1g/viewform?usp=pp_url&entry.192763438=https://www.metaculus.com/api/",
          "description": "Metaculus Data Needs form — the free Bot Benchmarking tier and bespoke grants are both requested here.",
          "title": "Data Needs Form Url",
          "type": "string"
        },
        "contact_email": {
          "default": "api-requests@metaculus.com",
          "description": "Metaculus API contact address.",
          "title": "Contact Email",
          "type": "string"
        },
        "unlock_note": {
          "default": "Submitting a forecast on a question permanently unlocks that question's text and resolution for your account, so access widens as you forecast.",
          "description": "How access grows without an upgrade.",
          "title": "Unlock Note",
          "type": "string"
        }
      },
      "required": [
        "code",
        "message"
      ],
      "title": "AccessHint",
      "type": "object"
    },
    "DataDownloadProbe": {
      "properties": {
        "attempted": {
          "title": "Attempted",
          "type": "boolean"
        },
        "post_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Post Id"
        },
        "http_status": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Http Status"
        },
        "accessible": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "True when the probe got a 2xx, false when it got any other status. Null means unknown: either no probe ran (attempted=false) or the probe ran but could not complete, so no status came back — `note` says which.",
          "title": "Accessible"
        },
        "note": {
          "title": "Note",
          "type": "string"
        }
      },
      "required": [
        "attempted",
        "note"
      ],
      "title": "DataDownloadProbe",
      "type": "object"
    }
  },
  "properties": {
    "user_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "User Id"
    },
    "user_id_source": {
      "description": "provided, users_me_endpoint, unavailable, or insufficient_budget. `insufficient_budget` means the probe was never run because too little of the invocation's time was left — it is not evidence that the id could not be resolved.",
      "title": "User Id Source",
      "type": "string"
    },
    "open_sampled": {
      "description": "Posts returned by the open sample. Read it together with `open_sample_status`: 0 with status `insufficient_budget` means NOT SAMPLED, not 'sampled and empty'.",
      "title": "Open Sampled",
      "type": "integer"
    },
    "open_with_cp": {
      "title": "Open With Cp",
      "type": "integer"
    },
    "open_sample_status": {
      "default": "sampled",
      "description": "`sampled` when the open feed sample ran (whatever it returned), `insufficient_budget` when it was skipped because too little of this invocation's time budget was left to start it. Nothing was sent in that case, so retrying is safe.",
      "enum": [
        "sampled",
        "insufficient_budget"
      ],
      "title": "Open Sample Status",
      "type": "string"
    },
    "resolved_sampled": {
      "description": "Posts returned by the resolved sample. Read it together with `resolved_sample_status`, exactly as for `open_sampled`.",
      "title": "Resolved Sampled",
      "type": "integer"
    },
    "resolved_with_cp": {
      "title": "Resolved With Cp",
      "type": "integer"
    },
    "resolved_sample_status": {
      "default": "sampled",
      "description": "`sampled` or `insufficient_budget`, with the same meaning as `open_sample_status`.",
      "enum": [
        "sampled",
        "insufficient_budget"
      ],
      "title": "Resolved Sample Status",
      "type": "string"
    },
    "data_download": {
      "$ref": "#/$defs/DataDownloadProbe"
    },
    "tier_suggestion": {
      "description": "Heuristic label: insufficient_budget (no sample ran, so there is no evidence either way), no_posts_in_sample (the samples ran and returned no posts at all), no_cp_in_sample, base_tier_likely, or expanded_tier_likely. Only the last three are statements about access.",
      "title": "Tier Suggestion",
      "type": "string"
    },
    "tier_suggestion_basis": {
      "description": "The counts and the Toolforest-side thresholds behind the suggestion. Metaculus publishes no tier endpoint and no such thresholds; these gate nothing, they only label the evidence.",
      "title": "Tier Suggestion Basis",
      "type": "string"
    },
    "notes": {
      "items": {
        "type": "string"
      },
      "title": "Notes",
      "type": "array"
    },
    "access_hint": {
      "anyOf": [
        {
          "$ref": "#/$defs/AccessHint"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    }
  },
  "required": [
    "user_id_source",
    "open_sampled",
    "open_with_cp",
    "resolved_sampled",
    "resolved_with_cp",
    "data_download",
    "tier_suggestion",
    "tier_suggestion_basis"
  ],
  "title": "AccessStatusResult",
  "type": "object"
}

# get_my_comments read

List your own Metaculus comments, optionally scoped to one post or to your private notes.

Full description
List comments you have written.

Metaculus requires comment reads to be filtered by author (or restricted to
staff authors), so this tool always sends `author=<your id>` — it cannot
fetch another user's comments.

Comment bodies are cut at 2000 characters; each comment says whether it was
(`text_truncated`). Set `is_private=True` for your private notes instead of
public comments.

Your user id is resolved automatically through Metaculus's undocumented
/api/users/me/ endpoint; pass `user_id` to skip that probe.
Parameter Type Required Description
user_id integer | null No Your Metaculus user id. Omit to resolve it automatically.
post_id integer | null No Only comments on this post.
is_private boolean | null No True for your private notes, False for public comments. Metaculus defaults to public when omitted.
sort "created_at" | "-created_at" | null No
limit integer No Default: 20
offset integer No Default: 0
Parameter schema (JSON)
{
  "properties": {
    "user_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Your Metaculus user id. Omit to resolve it automatically.",
      "title": "User Id"
    },
    "post_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only comments on this post.",
      "title": "Post Id"
    },
    "is_private": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "True for your private notes, False for public comments. Metaculus defaults to public when omitted.",
      "title": "Is Private"
    },
    "sort": {
      "anyOf": [
        {
          "enum": [
            "created_at",
            "-created_at"
          ],
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Sort"
    },
    "limit": {
      "default": 20,
      "maximum": 100,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    },
    "offset": {
      "default": 0,
      "minimum": 0,
      "title": "Offset",
      "type": "integer"
    }
  },
  "title": "GetMyCommentsParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "CommentSummary": {
      "properties": {
        "comment_id": {
          "title": "Comment Id",
          "type": "integer"
        },
        "post_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Post Id"
        },
        "post_url": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Post Url"
        },
        "created_at": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Created At"
        },
        "text": {
          "title": "Text",
          "type": "string"
        },
        "text_truncated": {
          "description": "True when the body was cut at 2000 characters.",
          "title": "Text Truncated",
          "type": "boolean"
        },
        "is_private": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Is Private"
        },
        "included_forecast": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Included Forecast"
        },
        "parent_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Parent Id"
        },
        "vote_score": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vote Score"
        }
      },
      "required": [
        "comment_id",
        "text",
        "text_truncated"
      ],
      "title": "CommentSummary",
      "type": "object"
    }
  },
  "properties": {
    "comments": {
      "items": {
        "$ref": "#/$defs/CommentSummary"
      },
      "title": "Comments",
      "type": "array"
    },
    "user_id": {
      "title": "User Id",
      "type": "integer"
    },
    "user_id_source": {
      "title": "User Id Source",
      "type": "string"
    },
    "returned": {
      "title": "Returned",
      "type": "integer"
    },
    "offset": {
      "title": "Offset",
      "type": "integer"
    },
    "limit": {
      "title": "Limit",
      "type": "integer"
    },
    "total_count": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Upstream total_count (root and child comments).",
      "title": "Total Count"
    },
    "next_offset": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Offset to request for the next page. Null whenever has_more is not true, and never equal to the offset you just requested.",
      "title": "Next Offset"
    },
    "has_more": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Whether another page exists. False when Metaculus returned fewer raw rows than `limit` (its `next` link lies on short pages) — judged on the upstream row count, so a page that lost malformed rows to client-side filtering still pages on. On a full page this is the upstream `next` link's presence; null only when the response carried no `next` field.",
      "title": "Has More"
    }
  },
  "required": [
    "comments",
    "user_id",
    "user_id_source",
    "returned",
    "offset",
    "limit"
  ],
  "title": "MyCommentsResult",
  "type": "object"
}

# get_my_predictions read

List the Metaculus posts you have forecast on, surfacing your own latest forecast — value, when you made it, when it stops standing — and resolutions on single-question posts; order_by='score' ranks them by your own forecasting performance.

Full description
List the posts you have forecast on.

This is the posts feed filtered by your own `forecaster_id`, so the same
compact summaries come back. `resolution` is populated for single-question
posts; groups and conditionals carry theirs on their subquestions, which
only get_question returns. Resolution text stays readable on questions you
have forecast on, which is every question this tool returns.

`my_forecast` answers "what did I say, and when": your latest forecast's
value alongside `start_time` (when you made it), `end_time` (when it stops
standing — the auto-withdrawal you scheduled through submit_forecast, or the
moment you withdrew it by hand with withdraw_forecast; a null is not proof
neither happened, see the field) and `withdrawn`. The value is compact and
mirrors `community_prediction`'s shape so the two read side by side —
`probability_yes`/`center` on binary, `option_probabilities` on multiple
choice, and median plus a 25th/75th interval (raw and in the question's own
units) on numeric, date and discrete questions; the stored 201-value CDF is
never returned. `start_time` is the LATEST forecast's timestamp, NOT the
first one you made on the question — full forecast history and per-forecast
scores stay download_question_data territory. On a group or conditional post
`my_forecast` is ONE subquestion's forecast, named by
`my_forecast_question_id`; get_question carries one per subquestion. It is
null when the response carried no forecast of yours for the post — and since
this feed is already filtered by your own forecaster_id, that is NOT evidence
you never forecast the post, only that Metaculus did not attach your
forecasts to that row. Ask get_question for the post when it happens.

`order_by='score'` ranks by your own forecasting performance. Metaculus
sorts server-side but does not return the score VALUE in this feed, so the
ranking is in the ORDER, not in a field; per-question personal scores come
from download_question_data.

Your user id is resolved automatically through Metaculus's undocumented
/api/users/me/ endpoint. Pass `user_id` to skip that probe, and see
`user_id_source` for which route was used.
Parameter Type Required Description
user_id integer | null No Your Metaculus user id. Omit to resolve it automatically.
statuses array<"upcoming" | "open" | "closed" | "resolved"> | null No
order_by string | null No Same values as list_questions. 'score' ranks by your own forecasting performance and works here because forecaster_id is always set.
limit integer No Default: 20
offset integer No Default: 0
Parameter schema (JSON)
{
  "properties": {
    "user_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Your Metaculus user id. Omit to resolve it automatically.",
      "title": "User Id"
    },
    "statuses": {
      "anyOf": [
        {
          "items": {
            "enum": [
              "upcoming",
              "open",
              "closed",
              "resolved"
            ],
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Statuses"
    },
    "order_by": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Same values as list_questions. 'score' ranks by your own forecasting performance and works here because forecaster_id is always set.",
      "title": "Order By"
    },
    "limit": {
      "default": 20,
      "maximum": 100,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    },
    "offset": {
      "default": 0,
      "minimum": 0,
      "title": "Offset",
      "type": "integer"
    }
  },
  "title": "GetMyPredictionsParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "AccessHint": {
      "description": "Machine-readable note that a response was shortened by access tier.",
      "properties": {
        "code": {
          "description": "tier_gated (data withheld for this token) or restricted_endpoint (the endpoint itself needs approval).",
          "title": "Code",
          "type": "string"
        },
        "message": {
          "description": "Human-readable explanation of what is missing.",
          "title": "Message",
          "type": "string"
        },
        "data_needs_form_url": {
          "default": "https://docs.google.com/forms/d/e/1FAIpQLSeJhtZzHl5qMvBjbXbatyaqoS4IU7RE0GGw_vlhs6I9syqn1g/viewform?usp=pp_url&entry.192763438=https://www.metaculus.com/api/",
          "description": "Metaculus Data Needs form — the free Bot Benchmarking tier and bespoke grants are both requested here.",
          "title": "Data Needs Form Url",
          "type": "string"
        },
        "contact_email": {
          "default": "api-requests@metaculus.com",
          "description": "Metaculus API contact address.",
          "title": "Contact Email",
          "type": "string"
        },
        "unlock_note": {
          "default": "Submitting a forecast on a question permanently unlocks that question's text and resolution for your account, so access widens as you forecast.",
          "description": "How access grows without an upgrade.",
          "title": "Unlock Note",
          "type": "string"
        }
      },
      "required": [
        "code",
        "message"
      ],
      "title": "AccessHint",
      "type": "object"
    },
    "CommunityPrediction": {
      "description": "The latest recency-weighted Community Prediction for one question.\n\nOnly the LATEST aggregation snapshot is returned; the aggregation history and\nthe full 201-value forecast_values array are dropped everywhere in this\ntoolkit. Metaculus does not label which quantiles ``interval_lower`` and\n``interval_upper`` represent, so they are passed through unlabelled.",
      "properties": {
        "forecaster_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Forecaster Count"
        },
        "as_of": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 start time of the latest aggregation.",
          "title": "As Of"
        },
        "center": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Aggregate center. For binary questions this is P(yes); for numeric/date/discrete questions it is an internal [0, 1] location; for multiple-choice questions it is the FIRST option's aggregate probability — read option_probabilities for the named per-option numbers. Null on a multiple-choice question whose options could not be paired with the aggregate, because then no option can be named.",
          "title": "Center"
        },
        "interval_lower": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower"
        },
        "interval_upper": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper"
        },
        "center_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center converted to the question's own units via question.scaling (numeric/date/discrete only; a POSIX timestamp for date questions). Null when the scaling is absent or degenerate.",
          "title": "Center Nominal"
        },
        "interval_lower_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower Nominal"
        },
        "interval_upper_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper Nominal"
        },
        "center_nominal_iso": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center_nominal as ISO 8601 (date questions only).",
          "title": "Center Nominal Iso"
        },
        "option_probabilities": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Per-option probabilities for multiple-choice questions, present only when the option list and the aggregate centers line up.",
          "title": "Option Probabilities"
        }
      },
      "title": "CommunityPrediction",
      "type": "object"
    },
    "MyForecast": {
      "description": "Your own LATEST forecast on one question, in the same compact shape as\nCommunityPrediction so the two can be read side by side.\n\nBuilt entirely from the ``my_forecasts.latest`` object Metaculus attaches to\nan authenticated posts response — personal data, which Metaculus does not\ngate by access tier, so this can be populated on a question whose Community\nPrediction is withheld. The forecast HISTORY is never read: ``start_time`` is\nthe latest forecast's timestamp, not the first one you made on the question,\nand on a continuous question the stored 201-value CDF is reduced to the\nquantiles below rather than returned. Full history and per-forecast scores\nare download_question_data territory.\n\nOne asymmetry with CommunityPrediction: Metaculus does not label which\nquantiles the CP's ``interval_lower``/``interval_upper`` represent, but it\ndoes label these — on a continuous question they are the 25th and 75th\npercentiles of your own stored distribution, whose median is ``center``.",
      "properties": {
        "start_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 time the LATEST forecast was made — not the first one you made on this question. Null only when Metaculus returned no usable timestamp.",
          "title": "Start Time"
        },
        "end_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 time this forecast stops standing — either an auto-withdrawal you set through submit_forecast's end_time, or the moment you withdrew it. Null USUALLY means no withdrawal time applies, but not only: Metaculus suppresses an end_time that falls after the question's own close time, and this toolkit reports null for one it cannot parse or cannot render as a timestamp. A null here is therefore not proof you never set one.",
          "title": "End Time"
        },
        "withdrawn": {
          "description": "True when end_time is non-null and already in the past as of this response, i.e. the forecast no longer counts toward the aggregate. False when end_time is null OR still in the future — a scheduled auto-withdrawal that has not fired yet reads false, and so does a forecast that simply stood until the question closed, whose end_time Metaculus suppresses to null: it stopped counting because the question closed, not because you withdrew it. A forecast you withdrew BEFORE the question closed keeps its end_time and so still reads true on a closed or resolved question.",
          "title": "Withdrawn",
          "type": "boolean"
        },
        "probability_yes": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your P(yes) on a BINARY question. Null on every other question type, and null on a binary question whose stored forecast did not come back as a usable P(no)/P(yes) pair. On a binary question `center` carries this same number under the Community Prediction's own field name; on other question types `center` carries a median or nothing while this stays null.",
          "title": "Probability Yes"
        },
        "center": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your forecast's center. For binary questions this is P(yes); for numeric/date/discrete questions it is the MEDIAN as an internal [0, 1] location. Null on multiple-choice questions (read option_probabilities — a per-option forecast has no single center), on any question type this toolkit does not summarize, and wherever the stored forecast carried no usable number.",
          "title": "Center"
        },
        "interval_lower": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your 25th percentile as an internal [0, 1] location, numeric/date/discrete questions only. Null on binary and multiple-choice: your own forecast there is a point estimate with no interval, unlike the Community Prediction, whose interval is the spread across forecasters.",
          "title": "Interval Lower"
        },
        "interval_upper": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your 75th percentile as an internal [0, 1] location, numeric/date/discrete questions only. Null on binary and multiple-choice — see interval_lower.",
          "title": "Interval Upper"
        },
        "center_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center converted to the question's own units via question.scaling (numeric/date/discrete only; a POSIX timestamp for date questions). Null when the scaling is absent or degenerate.",
          "title": "Center Nominal"
        },
        "interval_lower_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower Nominal"
        },
        "interval_upper_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper Nominal"
        },
        "center_nominal_iso": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center_nominal as ISO 8601 (date questions only).",
          "title": "Center Nominal Iso"
        },
        "option_probabilities": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your per-option probabilities for multiple-choice questions. The stored array is aligned to the question's ever-list of options (`all_options_ever`), so that is what these are paired against, or the current option list when the payload carries no ever-list — on a question that has had an option DELETED this map can therefore name an option that no longer appears in `options`. Null when the list used is not the same length as the stored array, since then no number can be attributed to an option. Metaculus permits a null probability on an individual option; such an option is OMITTED from this map, so the entries need not sum to 1.",
          "title": "Option Probabilities"
        }
      },
      "required": [
        "withdrawn"
      ],
      "title": "MyForecast",
      "type": "object"
    },
    "QuestionSummary": {
      "description": "Compact view of one post. Free text, aggregation history and CDFs are\nomitted — use get_question for a post's full detail.",
      "properties": {
        "post_id": {
          "title": "Post Id",
          "type": "integer"
        },
        "question_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Question id for single-question posts. Null for groups, conditionals and notebooks — forecast tools need a question id, so use get_question to list a group's subquestion ids.",
          "title": "Question Id"
        },
        "title": {
          "title": "Title",
          "type": "string"
        },
        "url": {
          "title": "Url",
          "type": "string"
        },
        "post_type": {
          "description": "question, group_of_questions, conditional, or notebook.",
          "title": "Post Type",
          "type": "string"
        },
        "question_type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "binary, numeric, discrete, date or multiple_choice.",
          "title": "Question Type"
        },
        "status": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Status"
        },
        "resolved": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Resolved"
        },
        "resolution": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Resolution of a single-question post. Always null for groups, conditionals and notebooks — their resolutions sit on the individual subquestions, which get_question returns.",
          "title": "Resolution"
        },
        "open_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Open Time"
        },
        "scheduled_close_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Scheduled Close Time"
        },
        "scheduled_resolve_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Scheduled Resolve Time"
        },
        "actual_resolve_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Actual Resolve Time"
        },
        "nr_forecasters": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Nr Forecasters"
        },
        "forecasts_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Forecasts Count"
        },
        "comment_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Comment Count"
        },
        "unit": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Unit"
        },
        "categories": {
          "items": {
            "type": "string"
          },
          "title": "Categories",
          "type": "array"
        },
        "tournaments": {
          "items": {
            "type": "string"
          },
          "title": "Tournaments",
          "type": "array"
        },
        "subquestion_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Subquestion Count"
        },
        "community_prediction": {
          "anyOf": [
            {
              "$ref": "#/$defs/CommunityPrediction"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Community Prediction for a single-question post. On a group or conditional post this is ONE subquestion's aggregate — the first that carried one and that the payload names with a question id, reported in community_prediction_question_id — not a post-level number, so do not quote it as the group's forecast. Use get_question for every subquestion's own aggregate."
        },
        "community_prediction_question_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Question id that community_prediction belongs to. Equals question_id on single-question posts, and names the stand-in subquestion on groups and conditionals, where the scan prefers a subquestion the payload gives a usable id. Null whenever community_prediction is null, and also on the malformed payload that carried no usable id for the question the aggregate came from.",
          "title": "Community Prediction Question Id"
        },
        "cp_access": {
          "description": "available when a Community Prediction came back for this post — on a group or conditional, for at least one subquestion, not all of them. absent when none did — usually the access tier, but also the case for a question nobody has forecast yet, and for notebooks. On groups, absent is weak evidence of gating: the feed only populates the top few subquestions, so ask get_question before concluding anything.",
          "title": "Cp Access",
          "type": "string"
        },
        "my_forecast": {
          "anyOf": [
            {
              "$ref": "#/$defs/MyForecast"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "YOUR own latest forecast on a single-question post. On a group or conditional post this is ONE subquestion's forecast — the first that carried one and that the payload names with a question id, reported in my_forecast_question_id — not a post-level forecast; use get_question for every subquestion's own. Null when the response carried no forecast of yours for this post: you have not forecast it, or Metaculus did not attach your forecasts to this response. Unlike community_prediction this is never withheld by access tier."
        },
        "my_forecast_question_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Question id that my_forecast belongs to. Equals question_id on single-question posts, and names the stand-in subquestion on groups and conditionals, where the scan prefers a subquestion the payload gives a usable id. Null whenever my_forecast is null, and also on the malformed payload that carried no usable id for the question the forecast came from.",
          "title": "My Forecast Question Id"
        }
      },
      "required": [
        "post_id",
        "title",
        "url",
        "post_type",
        "cp_access"
      ],
      "title": "QuestionSummary",
      "type": "object"
    }
  },
  "properties": {
    "questions": {
      "items": {
        "$ref": "#/$defs/QuestionSummary"
      },
      "title": "Questions",
      "type": "array"
    },
    "user_id": {
      "title": "User Id",
      "type": "integer"
    },
    "user_id_source": {
      "title": "User Id Source",
      "type": "string"
    },
    "returned": {
      "title": "Returned",
      "type": "integer"
    },
    "offset": {
      "title": "Offset",
      "type": "integer"
    },
    "limit": {
      "title": "Limit",
      "type": "integer"
    },
    "next_offset": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Offset to request for the next page. Null whenever has_more is not true, and never equal to the offset you just requested.",
      "title": "Next Offset"
    },
    "has_more": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Whether another page exists. False when Metaculus returned fewer raw rows than `limit` (its `next` link lies on short pages) — judged on the upstream row count, so a page that lost malformed rows to client-side filtering still pages on. On a full page this is the upstream `next` link's presence; null only when the response carried no `next` field.",
      "title": "Has More"
    },
    "cp_available_count": {
      "title": "Cp Available Count",
      "type": "integer"
    },
    "access_hint": {
      "anyOf": [
        {
          "$ref": "#/$defs/AccessHint"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    }
  },
  "required": [
    "questions",
    "user_id",
    "user_id_source",
    "returned",
    "offset",
    "limit",
    "cp_available_count"
  ],
  "title": "MyPredictionsResult",
  "type": "object"
}

# get_question read

Get one Metaculus post in full: description, resolution criteria, fine print, scaling, subquestions, the latest Community Prediction and your own latest forecast on each question you have forecast.

Full description
Retrieve one post's full detail by post id.

Returns the description, resolution criteria and fine print (each cut at
8000 characters, with anything cut named in `truncated_fields`), the
question's scaling (`range_min`, `range_max`, `zero_point`, open/closed
bounds, `inbound_outcome_count`) — everything submit_forecast needs — and
every subquestion of a group or conditional post, each with its own
question id.

Only the LATEST Community Prediction snapshot is returned: the aggregation
history, the 201-value forecast_values array and the `continuous_range` array
are all dropped. `cp_access` is `available` or `absent`, and an `access_hint`
appears only when the post yielded at least one question and every one of
them came back `absent` — a notebook post has no questions, so it gets no
hint rather than a hint saying its CP was withheld.

`my_forecast` carries your own latest forecast's value, `start_time` and
`end_time`, plus `withdrawn`, on every question whose payload carried a
forecast of yours. On a group or conditional post it sits on each
subquestion, the same way `resolution` does, so only the subquestions you
have forecast have one. `start_time` is the LATEST forecast's timestamp, not
the first one you made on the question; the full forecast history and
per-forecast scores come from download_question_data.

Closed questions you have never forecast on may come back without their text
or resolution — Metaculus unlocks those permanently once you forecast.
Parameter Type Required Description
post_id integer Yes Post id (the number in a metaculus.com/questions/<id>/ URL).
Parameter schema (JSON)
{
  "properties": {
    "post_id": {
      "description": "Post id (the number in a metaculus.com/questions/<id>/ URL).",
      "title": "Post Id",
      "type": "integer"
    }
  },
  "required": [
    "post_id"
  ],
  "title": "GetQuestionParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "AccessHint": {
      "description": "Machine-readable note that a response was shortened by access tier.",
      "properties": {
        "code": {
          "description": "tier_gated (data withheld for this token) or restricted_endpoint (the endpoint itself needs approval).",
          "title": "Code",
          "type": "string"
        },
        "message": {
          "description": "Human-readable explanation of what is missing.",
          "title": "Message",
          "type": "string"
        },
        "data_needs_form_url": {
          "default": "https://docs.google.com/forms/d/e/1FAIpQLSeJhtZzHl5qMvBjbXbatyaqoS4IU7RE0GGw_vlhs6I9syqn1g/viewform?usp=pp_url&entry.192763438=https://www.metaculus.com/api/",
          "description": "Metaculus Data Needs form — the free Bot Benchmarking tier and bespoke grants are both requested here.",
          "title": "Data Needs Form Url",
          "type": "string"
        },
        "contact_email": {
          "default": "api-requests@metaculus.com",
          "description": "Metaculus API contact address.",
          "title": "Contact Email",
          "type": "string"
        },
        "unlock_note": {
          "default": "Submitting a forecast on a question permanently unlocks that question's text and resolution for your account, so access widens as you forecast.",
          "description": "How access grows without an upgrade.",
          "title": "Unlock Note",
          "type": "string"
        }
      },
      "required": [
        "code",
        "message"
      ],
      "title": "AccessHint",
      "type": "object"
    },
    "CommunityPrediction": {
      "description": "The latest recency-weighted Community Prediction for one question.\n\nOnly the LATEST aggregation snapshot is returned; the aggregation history and\nthe full 201-value forecast_values array are dropped everywhere in this\ntoolkit. Metaculus does not label which quantiles ``interval_lower`` and\n``interval_upper`` represent, so they are passed through unlabelled.",
      "properties": {
        "forecaster_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Forecaster Count"
        },
        "as_of": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 start time of the latest aggregation.",
          "title": "As Of"
        },
        "center": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Aggregate center. For binary questions this is P(yes); for numeric/date/discrete questions it is an internal [0, 1] location; for multiple-choice questions it is the FIRST option's aggregate probability — read option_probabilities for the named per-option numbers. Null on a multiple-choice question whose options could not be paired with the aggregate, because then no option can be named.",
          "title": "Center"
        },
        "interval_lower": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower"
        },
        "interval_upper": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper"
        },
        "center_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center converted to the question's own units via question.scaling (numeric/date/discrete only; a POSIX timestamp for date questions). Null when the scaling is absent or degenerate.",
          "title": "Center Nominal"
        },
        "interval_lower_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower Nominal"
        },
        "interval_upper_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper Nominal"
        },
        "center_nominal_iso": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center_nominal as ISO 8601 (date questions only).",
          "title": "Center Nominal Iso"
        },
        "option_probabilities": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Per-option probabilities for multiple-choice questions, present only when the option list and the aggregate centers line up.",
          "title": "Option Probabilities"
        }
      },
      "title": "CommunityPrediction",
      "type": "object"
    },
    "MyForecast": {
      "description": "Your own LATEST forecast on one question, in the same compact shape as\nCommunityPrediction so the two can be read side by side.\n\nBuilt entirely from the ``my_forecasts.latest`` object Metaculus attaches to\nan authenticated posts response — personal data, which Metaculus does not\ngate by access tier, so this can be populated on a question whose Community\nPrediction is withheld. The forecast HISTORY is never read: ``start_time`` is\nthe latest forecast's timestamp, not the first one you made on the question,\nand on a continuous question the stored 201-value CDF is reduced to the\nquantiles below rather than returned. Full history and per-forecast scores\nare download_question_data territory.\n\nOne asymmetry with CommunityPrediction: Metaculus does not label which\nquantiles the CP's ``interval_lower``/``interval_upper`` represent, but it\ndoes label these — on a continuous question they are the 25th and 75th\npercentiles of your own stored distribution, whose median is ``center``.",
      "properties": {
        "start_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 time the LATEST forecast was made — not the first one you made on this question. Null only when Metaculus returned no usable timestamp.",
          "title": "Start Time"
        },
        "end_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 time this forecast stops standing — either an auto-withdrawal you set through submit_forecast's end_time, or the moment you withdrew it. Null USUALLY means no withdrawal time applies, but not only: Metaculus suppresses an end_time that falls after the question's own close time, and this toolkit reports null for one it cannot parse or cannot render as a timestamp. A null here is therefore not proof you never set one.",
          "title": "End Time"
        },
        "withdrawn": {
          "description": "True when end_time is non-null and already in the past as of this response, i.e. the forecast no longer counts toward the aggregate. False when end_time is null OR still in the future — a scheduled auto-withdrawal that has not fired yet reads false, and so does a forecast that simply stood until the question closed, whose end_time Metaculus suppresses to null: it stopped counting because the question closed, not because you withdrew it. A forecast you withdrew BEFORE the question closed keeps its end_time and so still reads true on a closed or resolved question.",
          "title": "Withdrawn",
          "type": "boolean"
        },
        "probability_yes": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your P(yes) on a BINARY question. Null on every other question type, and null on a binary question whose stored forecast did not come back as a usable P(no)/P(yes) pair. On a binary question `center` carries this same number under the Community Prediction's own field name; on other question types `center` carries a median or nothing while this stays null.",
          "title": "Probability Yes"
        },
        "center": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your forecast's center. For binary questions this is P(yes); for numeric/date/discrete questions it is the MEDIAN as an internal [0, 1] location. Null on multiple-choice questions (read option_probabilities — a per-option forecast has no single center), on any question type this toolkit does not summarize, and wherever the stored forecast carried no usable number.",
          "title": "Center"
        },
        "interval_lower": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your 25th percentile as an internal [0, 1] location, numeric/date/discrete questions only. Null on binary and multiple-choice: your own forecast there is a point estimate with no interval, unlike the Community Prediction, whose interval is the spread across forecasters.",
          "title": "Interval Lower"
        },
        "interval_upper": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your 75th percentile as an internal [0, 1] location, numeric/date/discrete questions only. Null on binary and multiple-choice — see interval_lower.",
          "title": "Interval Upper"
        },
        "center_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center converted to the question's own units via question.scaling (numeric/date/discrete only; a POSIX timestamp for date questions). Null when the scaling is absent or degenerate.",
          "title": "Center Nominal"
        },
        "interval_lower_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower Nominal"
        },
        "interval_upper_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper Nominal"
        },
        "center_nominal_iso": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center_nominal as ISO 8601 (date questions only).",
          "title": "Center Nominal Iso"
        },
        "option_probabilities": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your per-option probabilities for multiple-choice questions. The stored array is aligned to the question's ever-list of options (`all_options_ever`), so that is what these are paired against, or the current option list when the payload carries no ever-list — on a question that has had an option DELETED this map can therefore name an option that no longer appears in `options`. Null when the list used is not the same length as the stored array, since then no number can be attributed to an option. Metaculus permits a null probability on an individual option; such an option is OMITTED from this map, so the entries need not sum to 1.",
          "title": "Option Probabilities"
        }
      },
      "required": [
        "withdrawn"
      ],
      "title": "MyForecast",
      "type": "object"
    },
    "QuestionDetail": {
      "description": "One question (a post's own question, or one subquestion of a group or\nconditional) with its full text and scaling.",
      "properties": {
        "question_id": {
          "title": "Question Id",
          "type": "integer"
        },
        "title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Title"
        },
        "question_type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Question Type"
        },
        "status": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Status"
        },
        "resolution": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Resolution"
        },
        "label": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Subquestion label within a group, when present.",
          "title": "Label"
        },
        "description": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Description"
        },
        "resolution_criteria": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Resolution Criteria"
        },
        "fine_print": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Fine Print"
        },
        "unit": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Unit"
        },
        "options": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Options"
        },
        "open_lower_bound": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Open Lower Bound"
        },
        "open_upper_bound": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Open Upper Bound"
        },
        "inbound_outcome_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Inbound Outcome Count"
        },
        "range_min": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Range Min"
        },
        "range_max": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Range Max"
        },
        "zero_point": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Present (including 0.0) only for logarithmically scaled questions.",
          "title": "Zero Point"
        },
        "open_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Open Time"
        },
        "scheduled_close_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Scheduled Close Time"
        },
        "actual_close_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Actual Close Time"
        },
        "scheduled_resolve_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Scheduled Resolve Time"
        },
        "actual_resolve_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Actual Resolve Time"
        },
        "community_prediction": {
          "anyOf": [
            {
              "$ref": "#/$defs/CommunityPrediction"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "cp_access": {
          "title": "Cp Access",
          "type": "string"
        },
        "my_forecast": {
          "anyOf": [
            {
              "$ref": "#/$defs/MyForecast"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "YOUR own latest forecast on THIS question — on a group or conditional post each subquestion carries its own, so only the subquestions you have forecast have one. Null when the response carried no forecast of yours for this question."
        },
        "truncated_fields": {
          "description": "Which free-text fields were cut at 8000 characters.",
          "items": {
            "type": "string"
          },
          "title": "Truncated Fields",
          "type": "array"
        }
      },
      "required": [
        "question_id",
        "cp_access"
      ],
      "title": "QuestionDetail",
      "type": "object"
    }
  },
  "properties": {
    "post_id": {
      "title": "Post Id",
      "type": "integer"
    },
    "title": {
      "title": "Title",
      "type": "string"
    },
    "short_title": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Short Title"
    },
    "url": {
      "title": "Url",
      "type": "string"
    },
    "post_type": {
      "title": "Post Type",
      "type": "string"
    },
    "status": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Status"
    },
    "resolved": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Resolved"
    },
    "author_username": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Author Username"
    },
    "published_at": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Published At"
    },
    "nr_forecasters": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Nr Forecasters"
    },
    "forecasts_count": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Forecasts Count"
    },
    "comment_count": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Comment Count"
    },
    "categories": {
      "items": {
        "type": "string"
      },
      "title": "Categories",
      "type": "array"
    },
    "tournaments": {
      "items": {
        "type": "string"
      },
      "title": "Tournaments",
      "type": "array"
    },
    "question": {
      "anyOf": [
        {
          "$ref": "#/$defs/QuestionDetail"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "The post's own question, for single-question posts."
    },
    "subquestions": {
      "description": "Subquestions of a group, or the condition/child pair of a conditional. Empty for single-question posts and notebooks.",
      "items": {
        "$ref": "#/$defs/QuestionDetail"
      },
      "title": "Subquestions",
      "type": "array"
    },
    "access_hint": {
      "anyOf": [
        {
          "$ref": "#/$defs/AccessHint"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    }
  },
  "required": [
    "post_id",
    "title",
    "url",
    "post_type"
  ],
  "title": "GetQuestionResult",
  "type": "object"
}

# list_questions read

Browse Metaculus questions by status, type, category, tournament, time range and ordering, plus a best-effort text search.

Full description
Browse the Metaculus feed.

Discovery is primarily by structured filter: status, forecast type, category
slug, tournament slug, opening / publication / scheduled-resolution time
ranges, and ordering (`-hotness` for what is currently active,
`weekly_movement` and `divergence` for questions whose Community Prediction
is moving, `score` — which needs `forecaster_id` — for a forecaster's
performance ranking). A `search` parameter is also passed through, but it is
UNDOCUMENTED in Metaculus's published API: treat it as best-effort and fall
back to the structured filters if it disappoints.

Results are COMPACT: descriptions and aggregation histories are suppressed at
the source (`include_descriptions=false`, `include_cp_history=false`) and the
per-question forecast_values and continuous_range arrays are dropped here.
Call get_question for a post's full text.

The Community Prediction is always requested. Each post reports `cp_access`:
`available`, or `absent` when the response carried no aggregation for it —
most often the access tier, but also the case for a question nobody has
forecast yet. An `access_hint` explaining the upgrade path is emitted only
when the page returned at least one FORECASTABLE post and none of them
carried a CP: a page of notebooks carries no forecasts at all, so it is no
evidence of gating and gets no hint, and a page where some posts carried one
gets none either — `cp_access` already says which. Forecasting on a question
permanently unlocks that question's text and resolution for your account.

`my_forecast` appears on any post whose payload carried a forecast of yours:
your own latest forecast's value, `start_time` and `end_time`, plus
`withdrawn`. That is personal data and is never gated, so it can be present
on a post whose CP is `absent`. `start_time` is the LATEST forecast's
timestamp, not the first one you made — the full history is
download_question_data territory. On a group or conditional it is ONE
subquestion's forecast, named by `my_forecast_question_id`. A null
`my_forecast` usually means you have not forecast the post, but it can also
mean the feed did not attach your forecasts to that row; get_question
settles it.
Parameter Type Required Description
search string | null No Free-text search. UNDOCUMENTED: Metaculus's published API spec lists no search parameter, so this is best-effort and may stop working without notice. Prefer the structured filters when they fit.
statuses array<"upcoming" | "open" | "closed" | "resolved"> | null No Post lifecycle statuses to include.
forecast_type array<"binary" | "multiple_choice" | "numeric" | "discrete" | "date" | "conditional" | "group_of_questions" | "notebook"> | null No Post/question types to include, e.g. ['binary', 'numeric'].
categories array<string> | null No Category slugs, e.g. ['health-pandemics', 'nuclear'].
tournaments array<string> | null No Tournament slugs, e.g. ['metaculus-cup'].
forecaster_id integer | null No Only posts this user has forecast on.
not_forecaster_id integer | null No Only posts this user has NOT forecast on.
main_feed_only boolean | null No Restrict to posts suitable for the main feed.
open_time_after string | null No ISO 8601; posts that opened strictly after this.
open_time_before string | null No ISO 8601; posts that opened strictly before this.
published_at_after string | null No
published_at_before string | null No
scheduled_resolve_time_after string | null No
scheduled_resolve_time_before string | null No
order_by string | null No One of published_at, open_time, vote_score, comment_count, forecasts_count, scheduled_close_time, scheduled_resolve_time, user_last_forecasts_date, unread_comment_count, weekly_movement, divergence, hotness, score — prefix with '-' for descending. 'score' additionally requires forecaster_id.
limit integer No Posts per page. Default: 20
offset integer No Posts to skip. Default: 0
Parameter schema (JSON)
{
  "properties": {
    "search": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Free-text search. UNDOCUMENTED: Metaculus's published API spec lists no search parameter, so this is best-effort and may stop working without notice. Prefer the structured filters when they fit.",
      "title": "Search"
    },
    "statuses": {
      "anyOf": [
        {
          "items": {
            "enum": [
              "upcoming",
              "open",
              "closed",
              "resolved"
            ],
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Post lifecycle statuses to include.",
      "title": "Statuses"
    },
    "forecast_type": {
      "anyOf": [
        {
          "items": {
            "enum": [
              "binary",
              "multiple_choice",
              "numeric",
              "discrete",
              "date",
              "conditional",
              "group_of_questions",
              "notebook"
            ],
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Post/question types to include, e.g. ['binary', 'numeric'].",
      "title": "Forecast Type"
    },
    "categories": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Category slugs, e.g. ['health-pandemics', 'nuclear'].",
      "title": "Categories"
    },
    "tournaments": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Tournament slugs, e.g. ['metaculus-cup'].",
      "title": "Tournaments"
    },
    "forecaster_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only posts this user has forecast on.",
      "title": "Forecaster Id"
    },
    "not_forecaster_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only posts this user has NOT forecast on.",
      "title": "Not Forecaster Id"
    },
    "main_feed_only": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Restrict to posts suitable for the main feed.",
      "title": "Main Feed Only"
    },
    "open_time_after": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "ISO 8601; posts that opened strictly after this.",
      "title": "Open Time After"
    },
    "open_time_before": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "ISO 8601; posts that opened strictly before this.",
      "title": "Open Time Before"
    },
    "published_at_after": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Published At After"
    },
    "published_at_before": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Published At Before"
    },
    "scheduled_resolve_time_after": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Scheduled Resolve Time After"
    },
    "scheduled_resolve_time_before": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Scheduled Resolve Time Before"
    },
    "order_by": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "One of published_at, open_time, vote_score, comment_count, forecasts_count, scheduled_close_time, scheduled_resolve_time, user_last_forecasts_date, unread_comment_count, weekly_movement, divergence, hotness, score — prefix with '-' for descending. 'score' additionally requires forecaster_id.",
      "title": "Order By"
    },
    "limit": {
      "default": 20,
      "description": "Posts per page.",
      "maximum": 100,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    },
    "offset": {
      "default": 0,
      "description": "Posts to skip.",
      "minimum": 0,
      "title": "Offset",
      "type": "integer"
    }
  },
  "title": "ListQuestionsParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "AccessHint": {
      "description": "Machine-readable note that a response was shortened by access tier.",
      "properties": {
        "code": {
          "description": "tier_gated (data withheld for this token) or restricted_endpoint (the endpoint itself needs approval).",
          "title": "Code",
          "type": "string"
        },
        "message": {
          "description": "Human-readable explanation of what is missing.",
          "title": "Message",
          "type": "string"
        },
        "data_needs_form_url": {
          "default": "https://docs.google.com/forms/d/e/1FAIpQLSeJhtZzHl5qMvBjbXbatyaqoS4IU7RE0GGw_vlhs6I9syqn1g/viewform?usp=pp_url&entry.192763438=https://www.metaculus.com/api/",
          "description": "Metaculus Data Needs form — the free Bot Benchmarking tier and bespoke grants are both requested here.",
          "title": "Data Needs Form Url",
          "type": "string"
        },
        "contact_email": {
          "default": "api-requests@metaculus.com",
          "description": "Metaculus API contact address.",
          "title": "Contact Email",
          "type": "string"
        },
        "unlock_note": {
          "default": "Submitting a forecast on a question permanently unlocks that question's text and resolution for your account, so access widens as you forecast.",
          "description": "How access grows without an upgrade.",
          "title": "Unlock Note",
          "type": "string"
        }
      },
      "required": [
        "code",
        "message"
      ],
      "title": "AccessHint",
      "type": "object"
    },
    "CommunityPrediction": {
      "description": "The latest recency-weighted Community Prediction for one question.\n\nOnly the LATEST aggregation snapshot is returned; the aggregation history and\nthe full 201-value forecast_values array are dropped everywhere in this\ntoolkit. Metaculus does not label which quantiles ``interval_lower`` and\n``interval_upper`` represent, so they are passed through unlabelled.",
      "properties": {
        "forecaster_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Forecaster Count"
        },
        "as_of": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 start time of the latest aggregation.",
          "title": "As Of"
        },
        "center": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Aggregate center. For binary questions this is P(yes); for numeric/date/discrete questions it is an internal [0, 1] location; for multiple-choice questions it is the FIRST option's aggregate probability — read option_probabilities for the named per-option numbers. Null on a multiple-choice question whose options could not be paired with the aggregate, because then no option can be named.",
          "title": "Center"
        },
        "interval_lower": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower"
        },
        "interval_upper": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper"
        },
        "center_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center converted to the question's own units via question.scaling (numeric/date/discrete only; a POSIX timestamp for date questions). Null when the scaling is absent or degenerate.",
          "title": "Center Nominal"
        },
        "interval_lower_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower Nominal"
        },
        "interval_upper_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper Nominal"
        },
        "center_nominal_iso": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center_nominal as ISO 8601 (date questions only).",
          "title": "Center Nominal Iso"
        },
        "option_probabilities": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Per-option probabilities for multiple-choice questions, present only when the option list and the aggregate centers line up.",
          "title": "Option Probabilities"
        }
      },
      "title": "CommunityPrediction",
      "type": "object"
    },
    "MyForecast": {
      "description": "Your own LATEST forecast on one question, in the same compact shape as\nCommunityPrediction so the two can be read side by side.\n\nBuilt entirely from the ``my_forecasts.latest`` object Metaculus attaches to\nan authenticated posts response — personal data, which Metaculus does not\ngate by access tier, so this can be populated on a question whose Community\nPrediction is withheld. The forecast HISTORY is never read: ``start_time`` is\nthe latest forecast's timestamp, not the first one you made on the question,\nand on a continuous question the stored 201-value CDF is reduced to the\nquantiles below rather than returned. Full history and per-forecast scores\nare download_question_data territory.\n\nOne asymmetry with CommunityPrediction: Metaculus does not label which\nquantiles the CP's ``interval_lower``/``interval_upper`` represent, but it\ndoes label these — on a continuous question they are the 25th and 75th\npercentiles of your own stored distribution, whose median is ``center``.",
      "properties": {
        "start_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 time the LATEST forecast was made — not the first one you made on this question. Null only when Metaculus returned no usable timestamp.",
          "title": "Start Time"
        },
        "end_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ISO 8601 time this forecast stops standing — either an auto-withdrawal you set through submit_forecast's end_time, or the moment you withdrew it. Null USUALLY means no withdrawal time applies, but not only: Metaculus suppresses an end_time that falls after the question's own close time, and this toolkit reports null for one it cannot parse or cannot render as a timestamp. A null here is therefore not proof you never set one.",
          "title": "End Time"
        },
        "withdrawn": {
          "description": "True when end_time is non-null and already in the past as of this response, i.e. the forecast no longer counts toward the aggregate. False when end_time is null OR still in the future — a scheduled auto-withdrawal that has not fired yet reads false, and so does a forecast that simply stood until the question closed, whose end_time Metaculus suppresses to null: it stopped counting because the question closed, not because you withdrew it. A forecast you withdrew BEFORE the question closed keeps its end_time and so still reads true on a closed or resolved question.",
          "title": "Withdrawn",
          "type": "boolean"
        },
        "probability_yes": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your P(yes) on a BINARY question. Null on every other question type, and null on a binary question whose stored forecast did not come back as a usable P(no)/P(yes) pair. On a binary question `center` carries this same number under the Community Prediction's own field name; on other question types `center` carries a median or nothing while this stays null.",
          "title": "Probability Yes"
        },
        "center": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your forecast's center. For binary questions this is P(yes); for numeric/date/discrete questions it is the MEDIAN as an internal [0, 1] location. Null on multiple-choice questions (read option_probabilities — a per-option forecast has no single center), on any question type this toolkit does not summarize, and wherever the stored forecast carried no usable number.",
          "title": "Center"
        },
        "interval_lower": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your 25th percentile as an internal [0, 1] location, numeric/date/discrete questions only. Null on binary and multiple-choice: your own forecast there is a point estimate with no interval, unlike the Community Prediction, whose interval is the spread across forecasters.",
          "title": "Interval Lower"
        },
        "interval_upper": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your 75th percentile as an internal [0, 1] location, numeric/date/discrete questions only. Null on binary and multiple-choice — see interval_lower.",
          "title": "Interval Upper"
        },
        "center_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center converted to the question's own units via question.scaling (numeric/date/discrete only; a POSIX timestamp for date questions). Null when the scaling is absent or degenerate.",
          "title": "Center Nominal"
        },
        "interval_lower_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Lower Nominal"
        },
        "interval_upper_nominal": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Interval Upper Nominal"
        },
        "center_nominal_iso": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "center_nominal as ISO 8601 (date questions only).",
          "title": "Center Nominal Iso"
        },
        "option_probabilities": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Your per-option probabilities for multiple-choice questions. The stored array is aligned to the question's ever-list of options (`all_options_ever`), so that is what these are paired against, or the current option list when the payload carries no ever-list — on a question that has had an option DELETED this map can therefore name an option that no longer appears in `options`. Null when the list used is not the same length as the stored array, since then no number can be attributed to an option. Metaculus permits a null probability on an individual option; such an option is OMITTED from this map, so the entries need not sum to 1.",
          "title": "Option Probabilities"
        }
      },
      "required": [
        "withdrawn"
      ],
      "title": "MyForecast",
      "type": "object"
    },
    "QuestionSummary": {
      "description": "Compact view of one post. Free text, aggregation history and CDFs are\nomitted — use get_question for a post's full detail.",
      "properties": {
        "post_id": {
          "title": "Post Id",
          "type": "integer"
        },
        "question_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Question id for single-question posts. Null for groups, conditionals and notebooks — forecast tools need a question id, so use get_question to list a group's subquestion ids.",
          "title": "Question Id"
        },
        "title": {
          "title": "Title",
          "type": "string"
        },
        "url": {
          "title": "Url",
          "type": "string"
        },
        "post_type": {
          "description": "question, group_of_questions, conditional, or notebook.",
          "title": "Post Type",
          "type": "string"
        },
        "question_type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "binary, numeric, discrete, date or multiple_choice.",
          "title": "Question Type"
        },
        "status": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Status"
        },
        "resolved": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Resolved"
        },
        "resolution": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Resolution of a single-question post. Always null for groups, conditionals and notebooks — their resolutions sit on the individual subquestions, which get_question returns.",
          "title": "Resolution"
        },
        "open_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Open Time"
        },
        "scheduled_close_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Scheduled Close Time"
        },
        "scheduled_resolve_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Scheduled Resolve Time"
        },
        "actual_resolve_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Actual Resolve Time"
        },
        "nr_forecasters": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Nr Forecasters"
        },
        "forecasts_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Forecasts Count"
        },
        "comment_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Comment Count"
        },
        "unit": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Unit"
        },
        "categories": {
          "items": {
            "type": "string"
          },
          "title": "Categories",
          "type": "array"
        },
        "tournaments": {
          "items": {
            "type": "string"
          },
          "title": "Tournaments",
          "type": "array"
        },
        "subquestion_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Subquestion Count"
        },
        "community_prediction": {
          "anyOf": [
            {
              "$ref": "#/$defs/CommunityPrediction"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Community Prediction for a single-question post. On a group or conditional post this is ONE subquestion's aggregate — the first that carried one and that the payload names with a question id, reported in community_prediction_question_id — not a post-level number, so do not quote it as the group's forecast. Use get_question for every subquestion's own aggregate."
        },
        "community_prediction_question_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Question id that community_prediction belongs to. Equals question_id on single-question posts, and names the stand-in subquestion on groups and conditionals, where the scan prefers a subquestion the payload gives a usable id. Null whenever community_prediction is null, and also on the malformed payload that carried no usable id for the question the aggregate came from.",
          "title": "Community Prediction Question Id"
        },
        "cp_access": {
          "description": "available when a Community Prediction came back for this post — on a group or conditional, for at least one subquestion, not all of them. absent when none did — usually the access tier, but also the case for a question nobody has forecast yet, and for notebooks. On groups, absent is weak evidence of gating: the feed only populates the top few subquestions, so ask get_question before concluding anything.",
          "title": "Cp Access",
          "type": "string"
        },
        "my_forecast": {
          "anyOf": [
            {
              "$ref": "#/$defs/MyForecast"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "YOUR own latest forecast on a single-question post. On a group or conditional post this is ONE subquestion's forecast — the first that carried one and that the payload names with a question id, reported in my_forecast_question_id — not a post-level forecast; use get_question for every subquestion's own. Null when the response carried no forecast of yours for this post: you have not forecast it, or Metaculus did not attach your forecasts to this response. Unlike community_prediction this is never withheld by access tier."
        },
        "my_forecast_question_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Question id that my_forecast belongs to. Equals question_id on single-question posts, and names the stand-in subquestion on groups and conditionals, where the scan prefers a subquestion the payload gives a usable id. Null whenever my_forecast is null, and also on the malformed payload that carried no usable id for the question the forecast came from.",
          "title": "My Forecast Question Id"
        }
      },
      "required": [
        "post_id",
        "title",
        "url",
        "post_type",
        "cp_access"
      ],
      "title": "QuestionSummary",
      "type": "object"
    }
  },
  "properties": {
    "questions": {
      "items": {
        "$ref": "#/$defs/QuestionSummary"
      },
      "title": "Questions",
      "type": "array"
    },
    "returned": {
      "title": "Returned",
      "type": "integer"
    },
    "offset": {
      "title": "Offset",
      "type": "integer"
    },
    "limit": {
      "title": "Limit",
      "type": "integer"
    },
    "next_offset": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Offset to request for the next page. Null whenever has_more is not true, and never equal to the offset you just requested.",
      "title": "Next Offset"
    },
    "has_more": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Whether another page exists. False when Metaculus returned fewer raw rows than `limit` (its `next` link lies on short pages) — judged on the upstream row count, so a page that lost malformed rows to client-side filtering still pages on. On a full page this is the upstream `next` link's presence; null only when the response carried no `next` field.",
      "title": "Has More"
    },
    "cp_available_count": {
      "description": "How many of the returned posts carried a Community Prediction.",
      "title": "Cp Available Count",
      "type": "integer"
    },
    "access_hint": {
      "anyOf": [
        {
          "$ref": "#/$defs/AccessHint"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    }
  },
  "required": [
    "questions",
    "returned",
    "offset",
    "limit",
    "cp_available_count"
  ],
  "title": "QuestionListResult",
  "type": "object"
}

# post_comment write

Post a comment on a Metaculus post, optionally attaching your latest forecast or keeping it private.

Full description
Post a comment on a Metaculus post.

Takes a POST id (the number in a metaculus.com/questions/<id>/ URL). Set
`included_forecast=true` to attach your latest forecast to the comment —
the usual way to publish a rationale alongside a prediction — or
`is_private=true` to keep it as a note only you can see. `parent_comment_id`
makes it a reply.

Metaculus returns the created comment; `comment_id` is null if the response
carried no body.

If this invocation runs out of time after the request was sent, the error
says the comment MAY OR MAY NOT have been posted — check the post with
get_my_comments before retrying, so a retry does not post it twice.
Parameter Type Required Description
post_id integer Yes Post to comment on.
text string Yes Comment body (Markdown).
included_forecast boolean No Attach your latest forecast to the comment. Default: false
is_private boolean No True makes it a private note visible only to you. Default: false
parent_comment_id integer | null No Reply to this comment instead of starting a thread.
Parameter schema (JSON)
{
  "properties": {
    "post_id": {
      "description": "Post to comment on.",
      "title": "Post Id",
      "type": "integer"
    },
    "text": {
      "description": "Comment body (Markdown).",
      "minLength": 1,
      "title": "Text",
      "type": "string"
    },
    "included_forecast": {
      "default": false,
      "description": "Attach your latest forecast to the comment.",
      "title": "Included Forecast",
      "type": "boolean"
    },
    "is_private": {
      "default": false,
      "description": "True makes it a private note visible only to you.",
      "title": "Is Private",
      "type": "boolean"
    },
    "parent_comment_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Reply to this comment instead of starting a thread.",
      "title": "Parent Comment Id"
    }
  },
  "required": [
    "post_id",
    "text"
  ],
  "title": "PostCommentParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "comment_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Comment Id"
    },
    "post_id": {
      "title": "Post Id",
      "type": "integer"
    },
    "post_url": {
      "title": "Post Url",
      "type": "string"
    },
    "is_private": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Is Private"
    },
    "included_forecast": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Included Forecast"
    },
    "created_at": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Created At"
    },
    "message": {
      "title": "Message",
      "type": "string"
    }
  },
  "required": [
    "post_id",
    "post_url",
    "message"
  ],
  "title": "PostCommentResult",
  "type": "object"
}

# submit_forecast write

Submit a Metaculus forecast: a binary probability, multiple-choice probabilities, or a continuous distribution from percentiles.

Full description
Submit a forecast on one question.

Takes a QUESTION id, not a post id — for a group or conditional post, read
the subquestion ids from get_question first.

Supply exactly one of:

- `probability_yes` — binary questions, strictly between 0 and 1.
- `probability_yes_per_category` — multiple choice; the values must sum to 1
  and the labels must be the question's own options.
- `percentiles` — continuous questions (numeric, discrete, date). Give your
  distribution as percentile -> value in the question's own units, e.g.
  `{"percentile_25": 500, "50": 650, "percentile_75": 700}`. The Lambda
  fetches the question's scaling, maps each value to Metaculus's internal
  [0, 1] location (linear, or logarithmic when `zero_point` is set; date
  questions accept ISO 8601 strings or POSIX timestamps),
  interpolates linearly between the set points, and standardizes the result
  into the inbound_outcome_count+1 point CDF the API accepts. If your
  percentiles do not reach an OPEN bound, add `below_lower_bound` /
  `above_upper_bound` for the mass outside it; a CLOSED bound is anchored at
  zero outside mass automatically and rejects a non-zero value.
  Standardizing adds a 1%
  uniform component, which is what enforces the minimum step and the bound
  rules; it slightly flattens the distribution.
- `continuous_cdf` — a ready-made CDF, submitted UNCHANGED. It is checked
  against Metaculus's rules (length = inbound_outcome_count+1, monotonicity,
  minimum step, bound pinning) and rejected with the specific rule if it
  breaks one; it is never rescaled to fit. Its maximum-step check uses the
  looser 0.59 the API schema allows rather than the 0.2 the generation guide
  recommends — the spec states both, so a CDF between them is forwarded and
  Metaculus decides.

`end_time` sets a timestamp at which Metaculus automatically withdraws the
forecast. `return_cdf=true` echoes the submitted CDF back.

Forecasting permanently unlocks that question's text and resolution for your
account.

Forecast writes additionally need the account's own "API forecasting" switch
turned on (a one-button confirmation at
https://www.metaculus.com/accounts/settings/account/#api-forecasting-access,
separate from the data access tier, with a linked bot account as the route
for automated forecasting); the 403 you get before that says so and how.

If this invocation runs out of time mid-request, the error says which of two
things happened. When nothing reached Metaculus it says so outright and the
call is safe to repeat. When it cannot tell — the request had already been
sent — it says the forecast MAY OR MAY NOT have been recorded; read it back
with get_my_predictions before retrying, rather than assuming it failed — its
`my_forecast` reports your LATEST forecast's value, when it was made, and
`withdrawn`. Latest is not the same as standing: a forecast whose `end_time`
has already passed is still reported as the latest one, flagged
`withdrawn: true`, so check `withdrawn` before treating the value as live.
Parameter Type Required Description
question_id integer Yes QUESTION id, not post id. For a group or conditional post, take the id from get_question's subquestions.
post_id integer | null No Post that owns the question. Only needed for continuous forecasts, and only when it differs from question_id.
probability_yes number | null No Binary questions: P(yes), strictly between 0 and 1.
probability_yes_per_category object | null No Multiple-choice questions: probability per option label. Must sum to 1.
percentiles object | null No Continuous questions: your distribution as percentile -> value, e.g. {'percentile_25': 500, '50': 650, 'percentile_75': 700}. Values are in the question's own units; date questions accept an ISO 8601 string or a POSIX timestamp.
below_lower_bound number | null No Probability mass strictly below range_min. Required with percentiles when the question's lower bound is open and your percentiles do not reach it; must be 0 or omitted on a closed lower bound.
above_upper_bound number | null No Probability mass strictly above range_max.
continuous_cdf array<number> | null No Power users: a ready-made CDF with inbound_outcome_count+1 values (201 normally). Submitted unchanged after validation — it is NOT standardized.
end_time string | null No ISO 8601 timestamp at which Metaculus automatically withdraws this forecast.
return_cdf boolean No Echo the full submitted CDF back. It is long — leave off unless you need to inspect it. Default: false
Parameter schema (JSON)
{
  "properties": {
    "question_id": {
      "description": "QUESTION id, not post id. For a group or conditional post, take the id from get_question's subquestions.",
      "title": "Question Id",
      "type": "integer"
    },
    "post_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Post that owns the question. Only needed for continuous forecasts, and only when it differs from question_id.",
      "title": "Post Id"
    },
    "probability_yes": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Binary questions: P(yes), strictly between 0 and 1.",
      "title": "Probability Yes"
    },
    "probability_yes_per_category": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "number"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Multiple-choice questions: probability per option label. Must sum to 1.",
      "title": "Probability Yes Per Category"
    },
    "percentiles": {
      "anyOf": [
        {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ]
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Continuous questions: your distribution as percentile -> value, e.g. {'percentile_25': 500, '50': 650, 'percentile_75': 700}. Values are in the question's own units; date questions accept an ISO 8601 string or a POSIX timestamp.",
      "title": "Percentiles"
    },
    "below_lower_bound": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Probability mass strictly below range_min. Required with percentiles when the question's lower bound is open and your percentiles do not reach it; must be 0 or omitted on a closed lower bound.",
      "title": "Below Lower Bound"
    },
    "above_upper_bound": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Probability mass strictly above range_max.",
      "title": "Above Upper Bound"
    },
    "continuous_cdf": {
      "anyOf": [
        {
          "items": {
            "type": "number"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Power users: a ready-made CDF with inbound_outcome_count+1 values (201 normally). Submitted unchanged after validation — it is NOT standardized.",
      "title": "Continuous Cdf"
    },
    "end_time": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "ISO 8601 timestamp at which Metaculus automatically withdraws this forecast.",
      "title": "End Time"
    },
    "return_cdf": {
      "default": false,
      "description": "Echo the full submitted CDF back. It is long — leave off unless you need to inspect it.",
      "title": "Return Cdf",
      "type": "boolean"
    }
  },
  "required": [
    "question_id"
  ],
  "title": "SubmitForecastParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "question_id": {
      "title": "Question Id",
      "type": "integer"
    },
    "mode": {
      "description": "binary, multiple_choice, continuous_percentiles, or continuous_cdf.",
      "title": "Mode",
      "type": "string"
    },
    "end_time": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "End Time"
    },
    "cdf_length": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cdf Length"
    },
    "cdf_first": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cdf First"
    },
    "cdf_last": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cdf Last"
    },
    "standardized": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "True when the CDF was built from percentiles and passed through standardize_cdf. False when a raw continuous_cdf was submitted unchanged. Null for binary and multiple-choice forecasts.",
      "title": "Standardized"
    },
    "continuous_cdf": {
      "anyOf": [
        {
          "items": {
            "type": "number"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "The submitted CDF, only when return_cdf was true.",
      "title": "Continuous Cdf"
    },
    "message": {
      "title": "Message",
      "type": "string"
    }
  },
  "required": [
    "question_id",
    "mode",
    "message"
  ],
  "title": "SubmitForecastResult",
  "type": "object"
}

# withdraw_forecast write

Withdraw your current Metaculus forecast on one or several questions.

Full description
Withdraw your current forecast on one or more questions.

Takes QUESTION ids (up to 50 per call — a Toolforest-side cap; Metaculus
documents no limit) and sends them in a single request, which is how group
and conditional questions are withdrawn together.

Withdrawing removes your standing forecast from the aggregate going forward;
it does not erase your forecast history. Metaculus returns no per-question
result, so `withdrawn_count` is the size of the accepted request, not
confirmation that each question had a live forecast to withdraw.

All the ids go in ONE request, so a time-out is all-or-nothing rather than
partial — but which of the two it is may be unknown. When the invocation
runs out of time after the request was sent, the error says the withdrawal
MAY OR MAY NOT have been applied; check with get_my_predictions before
retrying — and read its `withdrawn` flag, not the presence of `my_forecast`,
because a withdrawn forecast Metaculus still reports as your latest comes
back with a value and `withdrawn: true` rather than as a null `my_forecast`.
Parameter Type Required Description
question_ids array<integer> Yes QUESTION ids whose current forecasts should be withdrawn.
Parameter schema (JSON)
{
  "properties": {
    "question_ids": {
      "description": "QUESTION ids whose current forecasts should be withdrawn.",
      "items": {
        "type": "integer"
      },
      "maxItems": 50,
      "minItems": 1,
      "title": "Question Ids",
      "type": "array"
    }
  },
  "required": [
    "question_ids"
  ],
  "title": "WithdrawForecastParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "question_ids": {
      "items": {
        "type": "integer"
      },
      "title": "Question Ids",
      "type": "array"
    },
    "withdrawn_count": {
      "description": "How many question ids were sent in the accepted request. Metaculus returns no per-question result, so this is the request size, not a confirmation that each had a live forecast.",
      "title": "Withdrawn Count",
      "type": "integer"
    },
    "message": {
      "title": "Message",
      "type": "string"
    }
  },
  "required": [
    "question_ids",
    "withdrawn_count",
    "message"
  ],
  "title": "WithdrawForecastResult",
  "type": "object"
}