{
  "openapi": "3.1.1",
  "info": {
    "title": "Decision Simulator API",
    "version": "1.0.0",
    "summary": "Compare 2–6 choices by expected value, worst case, best case and minimax regret.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://decisionsimulator.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Compare 2–6 choices by expected value, worst case, best case and minimax regret.",
        "description": "Give each choice a worst, most likely and best outcome (money, hours, points…). The simulator computes expected values with PERT or triangular weights (or your own probabilities), then applies maximin, maximax, minimax regret and Laplace rules and explains which rule picks which choice.\n\nMethodology:\n- Each choice has three scenario outcomes: worst (W), most likely (M) and best (B).\n- PERT expected value = (W + 4M + B) ÷ 6, standard deviation ≈ (B − W) ÷ 6.\n- Triangular expected value = (W + M + B) ÷ 3, standard deviation = √((W² + M² + B² − WM − WB − MB) ÷ 18).\n- Custom: probabilities are normalised to sum to 1; EV = Σ pᵢ·xᵢ, standard deviation = √(Σ pᵢ·(xᵢ − EV)²).\n- Maximin picks the best worst case; maximax the best best case; Laplace the best unweighted average (W + M + B) ÷ 3.\n- Minimax regret treats worst / likely / best as three shared states of the world: regret = (best outcome of any choice in that state) − (this choice’s outcome); the choice with the smallest maximum regret wins.\n- When lower values are better, “best” means lowest everywhere. Ties go to the choice listed first. The recommendation is the expected-value pick.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "decision_simulator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionSimulatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Job offers: first-year net gain",
                  "value": {
                    "goal": "maximize",
                    "method": "pert",
                    "unit": "EUR",
                    "choices": [
                      {
                        "name": "Stay in current job",
                        "worst": 48000,
                        "likely": 50000,
                        "best": 52000
                      },
                      {
                        "name": "Startup offer",
                        "worst": 30000,
                        "likely": 58000,
                        "best": 90000
                      },
                      {
                        "name": "Corporate offer",
                        "worst": 50000,
                        "likely": 55000,
                        "best": 60000
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Commute: travel minutes per day",
                  "value": {
                    "goal": "minimize",
                    "method": "custom",
                    "unit": "minutes",
                    "choices": [
                      {
                        "name": "Car",
                        "worst": 90,
                        "likely": 45,
                        "best": 35,
                        "pWorst": 10,
                        "pLikely": 70,
                        "pBest": 20
                      },
                      {
                        "name": "Train",
                        "worst": 70,
                        "likely": 55,
                        "best": 50,
                        "pWorst": 15,
                        "pLikely": 75,
                        "pBest": 10
                      },
                      {
                        "name": "Bike",
                        "worst": 60,
                        "likely": 58,
                        "best": 55,
                        "pWorst": 20,
                        "pLikely": 60,
                        "pBest": 20
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionSimulatorResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "DecisionSimulatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "goal": {
            "title": "Higher values are",
            "type": "string",
            "enum": [
              "maximize",
              "minimize"
            ],
            "default": "maximize"
          },
          "method": {
            "title": "Expected value weights",
            "type": "string",
            "enum": [
              "pert",
              "triangular",
              "custom"
            ],
            "default": "pert"
          },
          "unit": {
            "title": "Unit of the values",
            "type": "string",
            "maxLength": 20,
            "default": "EUR"
          },
          "choices": {
            "title": "Choices",
            "description": "Worst/likely/best outcome per choice. Probabilities (%) are only used with “My own probabilities” and are normalised to sum to 100.",
            "type": "array",
            "minItems": 2,
            "maxItems": 6,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Choice",
                  "type": "string"
                },
                "worst": {
                  "title": "Worst",
                  "type": "number"
                },
                "likely": {
                  "title": "Most likely",
                  "type": "number"
                },
                "best": {
                  "title": "Best",
                  "type": "number"
                },
                "pWorst": {
                  "title": "P(worst) %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                },
                "pLikely": {
                  "title": "P(likely) %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                },
                "pBest": {
                  "title": "P(best) %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                }
              },
              "required": [
                "name",
                "worst",
                "likely",
                "best"
              ]
            }
          }
        },
        "required": [
          "choices"
        ]
      },
      "DecisionSimulatorResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "goal",
              "method",
              "unit",
              "choices",
              "picks",
              "recommendation",
              "rulesInAgreement",
              "explanation"
            ],
            "properties": {
              "goal": {
                "type": "string",
                "enum": [
                  "maximize",
                  "minimize"
                ]
              },
              "method": {
                "type": "string",
                "enum": [
                  "pert",
                  "triangular",
                  "custom"
                ]
              },
              "unit": {
                "type": "string"
              },
              "choices": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "worst",
                    "likely",
                    "best",
                    "expectedValue",
                    "standardDeviation",
                    "average",
                    "maxRegret",
                    "weights",
                    "rankByExpectedValue"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "worst": {
                      "type": "number"
                    },
                    "likely": {
                      "type": "number"
                    },
                    "best": {
                      "type": "number"
                    },
                    "expectedValue": {
                      "type": "number"
                    },
                    "standardDeviation": {
                      "type": "number",
                      "description": "Analytical spread of the chosen distribution (PERT: (best − worst)/6; triangular: √((a²+b²+c²−ab−ac−bc)/18); custom: discrete)."
                    },
                    "average": {
                      "type": "number",
                      "description": "Unweighted mean of worst, likely and best (Laplace rule)."
                    },
                    "maxRegret": {
                      "type": "number",
                      "description": "Largest shortfall versus the best choice in any of the three scenarios."
                    },
                    "weights": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": false,
                      "required": [
                        "worst",
                        "likely",
                        "best"
                      ],
                      "properties": {
                        "worst": {
                          "type": "number"
                        },
                        "likely": {
                          "type": "number"
                        },
                        "best": {
                          "type": "number"
                        }
                      },
                      "description": "Normalised probabilities used (null when not applicable)."
                    },
                    "rankByExpectedValue": {
                      "type": "integer",
                      "minimum": 1
                    }
                  }
                }
              },
              "picks": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "expectedValue",
                  "maximin",
                  "maximax",
                  "minimaxRegret",
                  "laplace"
                ],
                "properties": {
                  "expectedValue": {
                    "type": "string"
                  },
                  "maximin": {
                    "type": "string",
                    "description": "Best worst case (pessimist)."
                  },
                  "maximax": {
                    "type": "string",
                    "description": "Best best case (optimist)."
                  },
                  "minimaxRegret": {
                    "type": "string"
                  },
                  "laplace": {
                    "type": "string",
                    "description": "Best unweighted average."
                  }
                }
              },
              "recommendation": {
                "type": "string"
              },
              "rulesInAgreement": {
                "type": "integer",
                "minimum": 1,
                "maximum": 5,
                "description": "How many of the 5 rules pick the recommended choice."
              },
              "explanation": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}