{
  "openapi": "3.1.0",
  "info": {
    "title": "Founder Scorecard API",
    "version": "1.0.0",
    "description": "Four free checks for any business idea: the MOAT score, price headroom from your close rate, whether customers fund growth, and what an old email list is worth.\n\nFree, no API key, CORS open. Fair use: about 120 requests per minute per IP. Also available as MCP tools at https://free-agent-tools.vercel.app/mcp"
  },
  "servers": [
    {
      "url": "https://fund-fix-flee.vercel.app"
    }
  ],
  "paths": {
    "/api/moat": {
      "get": {
        "operationId": "moatIdeaScore",
        "summary": "Score a business idea with MOAT (Margin, Operations, Advantage, TAM): fund it, fix it, or flee it",
        "description": "Rate four factors from 1 to 10. Total 30+ = FUND IT, 20-29 = FIX IT, under 20 = FLEE IT. Returns the weakest factor, how to fix it, and red flags from three yes/no questions (real pain, buyers have money, founder willing to suffer).\n\nExample: https://fund-fix-flee.vercel.app/api/moat?margin=7&operations=4&advantage=6&tam=8&pain=true&money=true&suffer=true",
        "parameters": [
          {
            "name": "margin",
            "in": "query",
            "required": true,
            "description": "Net margin potential, 1-10 (10 = very high margin).",
            "schema": {
              "type": "number",
              "description": "Net margin potential, 1-10 (10 = very high margin).",
              "minimum": 1,
              "maximum": 10
            }
          },
          {
            "name": "operations",
            "in": "query",
            "required": true,
            "description": "How easily it runs without the founder, 1-10.",
            "schema": {
              "type": "number",
              "description": "How easily it runs without the founder, 1-10.",
              "minimum": 1,
              "maximum": 10
            }
          },
          {
            "name": "advantage",
            "in": "query",
            "required": true,
            "description": "Hard-to-copy edge (distribution, data, expertise), 1-10.",
            "schema": {
              "type": "number",
              "description": "Hard-to-copy edge (distribution, data, expertise), 1-10.",
              "minimum": 1,
              "maximum": 10
            }
          },
          {
            "name": "tam",
            "in": "query",
            "required": true,
            "description": "Market size / proof that people buy, 1-10.",
            "schema": {
              "type": "number",
              "description": "Market size / proof that people buy, 1-10.",
              "minimum": 1,
              "maximum": 10
            }
          },
          {
            "name": "pain",
            "in": "query",
            "required": false,
            "description": "Does it fix a measurable pain?",
            "schema": {
              "type": "boolean",
              "description": "Does it fix a measurable pain?",
              "default": true
            }
          },
          {
            "name": "money",
            "in": "query",
            "required": false,
            "description": "Do buyers have money to spend?",
            "schema": {
              "type": "boolean",
              "description": "Do buyers have money to spend?",
              "default": true
            }
          },
          {
            "name": "suffer",
            "in": "query",
            "required": false,
            "description": "Is the founder willing to push through a long, hard build?",
            "schema": {
              "type": "boolean",
              "description": "Is the founder willing to push through a long, hard build?",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      },
      "post": {
        "operationId": "moatIdeaScorePost",
        "summary": "Score a business idea with MOAT (Margin, Operations, Advantage, TAM): fund it, fix it, or flee it (JSON body)",
        "description": "Rate four factors from 1 to 10. Total 30+ = FUND IT, 20-29 = FIX IT, under 20 = FLEE IT. Returns the weakest factor, how to fix it, and red flags from three yes/no questions (real pain, buyers have money, founder willing to suffer).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "margin",
                  "operations",
                  "advantage",
                  "tam"
                ],
                "properties": {
                  "margin": {
                    "type": "number",
                    "description": "Net margin potential, 1-10 (10 = very high margin).",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "operations": {
                    "type": "number",
                    "description": "How easily it runs without the founder, 1-10.",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "advantage": {
                    "type": "number",
                    "description": "Hard-to-copy edge (distribution, data, expertise), 1-10.",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "tam": {
                    "type": "number",
                    "description": "Market size / proof that people buy, 1-10.",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "pain": {
                    "type": "boolean",
                    "description": "Does it fix a measurable pain?",
                    "default": true
                  },
                  "money": {
                    "type": "boolean",
                    "description": "Do buyers have money to spend?",
                    "default": true
                  },
                  "suffer": {
                    "type": "boolean",
                    "description": "Is the founder willing to push through a long, hard build?",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      }
    },
    "/api/price": {
      "get": {
        "operationId": "priceHeadroom",
        "summary": "Estimate price headroom from sales close rate, and the profit effect of a price rise",
        "description": "Uses the close-rate rule of thumb (80%+ close = way underpriced, ~30% = about right, under 25% = sales problem). Returns a suggested price range, the profit multiple after a rise with some customers lost, and the break-even customer loss percentage.\n\nExample: https://fund-fix-flee.vercel.app/api/price?closeRate=70&price=500&netMargin=15&newPriceMultiple=1.5&customersLost=20",
        "parameters": [
          {
            "name": "closeRate",
            "in": "query",
            "required": true,
            "description": "Percent of sales calls or proposals that close, 0-100.",
            "schema": {
              "type": "number",
              "description": "Percent of sales calls or proposals that close, 0-100.",
              "minimum": 0,
              "maximum": 100
            }
          },
          {
            "name": "price",
            "in": "query",
            "required": true,
            "description": "Current price, any currency.",
            "schema": {
              "type": "number",
              "description": "Current price, any currency.",
              "minimum": 0
            }
          },
          {
            "name": "netMargin",
            "in": "query",
            "required": false,
            "description": "Net profit margin percent today.",
            "schema": {
              "type": "number",
              "description": "Net profit margin percent today.",
              "default": 15,
              "minimum": 0.1,
              "maximum": 99
            }
          },
          {
            "name": "newPriceMultiple",
            "in": "query",
            "required": false,
            "description": "New price as a multiple of the current price (1.5 = +50%).",
            "schema": {
              "type": "number",
              "description": "New price as a multiple of the current price (1.5 = +50%).",
              "default": 1.5,
              "minimum": 0.1,
              "maximum": 10
            }
          },
          {
            "name": "customersLost",
            "in": "query",
            "required": false,
            "description": "Percent of customers you expect to lose after the rise.",
            "schema": {
              "type": "number",
              "description": "Percent of customers you expect to lose after the rise.",
              "default": 20,
              "minimum": 0,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      },
      "post": {
        "operationId": "priceHeadroomPost",
        "summary": "Estimate price headroom from sales close rate, and the profit effect of a price rise (JSON body)",
        "description": "Uses the close-rate rule of thumb (80%+ close = way underpriced, ~30% = about right, under 25% = sales problem). Returns a suggested price range, the profit multiple after a rise with some customers lost, and the break-even customer loss percentage.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "closeRate",
                  "price"
                ],
                "properties": {
                  "closeRate": {
                    "type": "number",
                    "description": "Percent of sales calls or proposals that close, 0-100.",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "price": {
                    "type": "number",
                    "description": "Current price, any currency.",
                    "minimum": 0
                  },
                  "netMargin": {
                    "type": "number",
                    "description": "Net profit margin percent today.",
                    "default": 15,
                    "minimum": 0.1,
                    "maximum": 99
                  },
                  "newPriceMultiple": {
                    "type": "number",
                    "description": "New price as a multiple of the current price (1.5 = +50%).",
                    "default": 1.5,
                    "minimum": 0.1,
                    "maximum": 10
                  },
                  "customersLost": {
                    "type": "number",
                    "description": "Percent of customers you expect to lose after the rise.",
                    "default": 20,
                    "minimum": 0,
                    "maximum": 100
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      }
    },
    "/api/cash": {
      "get": {
        "operationId": "thirtyDayCashCheck",
        "summary": "Check whether a new customer's first 30 days of cash pays for acquiring and serving them (2x rule)",
        "description": "Ratio of cash collected in a customer's first 30 days to acquisition cost plus 30-day cost to serve. 2x+ = SELF-FUNDING, 1-2x = BREAK-EVEN, under 1x = CASH-HUNGRY. Returns the gap to 2x and tips.\n\nExample: https://fund-fix-flee.vercel.app/api/cash?cash30=400&cac=250&cogs30=100",
        "parameters": [
          {
            "name": "cash30",
            "in": "query",
            "required": true,
            "description": "Cash collected from a new customer in their first 30 days.",
            "schema": {
              "type": "number",
              "description": "Cash collected from a new customer in their first 30 days.",
              "minimum": 0
            }
          },
          {
            "name": "cac",
            "in": "query",
            "required": true,
            "description": "Cost to acquire one customer.",
            "schema": {
              "type": "number",
              "description": "Cost to acquire one customer.",
              "minimum": 0
            }
          },
          {
            "name": "cogs30",
            "in": "query",
            "required": false,
            "description": "Cost to serve that customer for their first 30 days.",
            "schema": {
              "type": "number",
              "description": "Cost to serve that customer for their first 30 days.",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      },
      "post": {
        "operationId": "thirtyDayCashCheckPost",
        "summary": "Check whether a new customer's first 30 days of cash pays for acquiring and serving them (2x rule) (JSON body)",
        "description": "Ratio of cash collected in a customer's first 30 days to acquisition cost plus 30-day cost to serve. 2x+ = SELF-FUNDING, 1-2x = BREAK-EVEN, under 1x = CASH-HUNGRY. Returns the gap to 2x and tips.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "cash30",
                  "cac"
                ],
                "properties": {
                  "cash30": {
                    "type": "number",
                    "description": "Cash collected from a new customer in their first 30 days.",
                    "minimum": 0
                  },
                  "cac": {
                    "type": "number",
                    "description": "Cost to acquire one customer.",
                    "minimum": 0
                  },
                  "cogs30": {
                    "type": "number",
                    "description": "Cost to serve that customer for their first 30 days.",
                    "default": 0,
                    "minimum": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      }
    },
    "/api/email-list": {
      "get": {
        "operationId": "oldEmailListValue",
        "summary": "Estimate what one reactivation offer to an old customer or email list might bring in",
        "description": "Low / mid / high scenarios (0.5x, 1x, 2x the buy rate) for buyers and revenue, plus an optional partner revenue-share split.\n\nExample: https://fund-fix-flee.vercel.app/api/email-list?contacts=3000&orderValue=80&reachable=70&buyRate=1&partnerShare=20",
        "parameters": [
          {
            "name": "contacts",
            "in": "query",
            "required": true,
            "description": "Number of past contacts on the list.",
            "schema": {
              "type": "number",
              "description": "Number of past contacts on the list.",
              "minimum": 0
            }
          },
          {
            "name": "orderValue",
            "in": "query",
            "required": true,
            "description": "Average order value of the offer.",
            "schema": {
              "type": "number",
              "description": "Average order value of the offer.",
              "minimum": 0
            }
          },
          {
            "name": "reachable",
            "in": "query",
            "required": false,
            "description": "Percent of contacts still reachable.",
            "schema": {
              "type": "number",
              "description": "Percent of contacts still reachable.",
              "default": 70,
              "minimum": 0,
              "maximum": 100
            }
          },
          {
            "name": "buyRate",
            "in": "query",
            "required": false,
            "description": "Expected percent of reached contacts who buy.",
            "schema": {
              "type": "number",
              "description": "Expected percent of reached contacts who buy.",
              "default": 1,
              "minimum": 0,
              "maximum": 100
            }
          },
          {
            "name": "partnerShare",
            "in": "query",
            "required": false,
            "description": "Optional partner revenue share percent.",
            "schema": {
              "type": "number",
              "description": "Optional partner revenue share percent.",
              "default": 0,
              "minimum": 0,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      },
      "post": {
        "operationId": "oldEmailListValuePost",
        "summary": "Estimate what one reactivation offer to an old customer or email list might bring in (JSON body)",
        "description": "Low / mid / high scenarios (0.5x, 1x, 2x the buy rate) for buyers and revenue, plus an optional partner revenue-share split.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "contacts",
                  "orderValue"
                ],
                "properties": {
                  "contacts": {
                    "type": "number",
                    "description": "Number of past contacts on the list.",
                    "minimum": 0
                  },
                  "orderValue": {
                    "type": "number",
                    "description": "Average order value of the offer.",
                    "minimum": 0
                  },
                  "reachable": {
                    "type": "number",
                    "description": "Percent of contacts still reachable.",
                    "default": 70,
                    "minimum": 0,
                    "maximum": 100
                  },
                  "buyRate": {
                    "type": "number",
                    "description": "Expected percent of reached contacts who buy.",
                    "default": 1,
                    "minimum": 0,
                    "maximum": 100
                  },
                  "partnerShare": {
                    "type": "number",
                    "description": "Optional partner revenue share percent.",
                    "default": 0,
                    "minimum": 0,
                    "maximum": 100
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result as JSON. Always includes a `disclaimer` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input. The body explains what to send and gives an example."
          },
          "429": {
            "description": "Too many requests from one IP. Retry after the Retry-After seconds."
          }
        }
      }
    }
  }
}