{
  "openapi": "3.1.0",
  "info": {
    "title": "SaaS Bill Cutter API",
    "version": "1.0.0",
    "description": "Enter what you pay for business software. See the open-source swap, the real savings, and the catches.\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://saas-bill-cutter.vercel.app"
    }
  ],
  "paths": {
    "/api/calculate": {
      "get": {
        "operationId": "saasSelfHostSavings",
        "summary": "Should I replace paid SaaS (Mixpanel, Semrush, Calendly, Intercom...) with a self-hosted open-source alternative? Savings and payback",
        "description": "Give monthly spend per tool id. Returns each open-source swap (repo, license, caveat), yearly paid cost, hosting cost, one-time setup hours and cost, first-year and ongoing net savings, break-even months, and a verdict: SWITCH (payback <= 6 months and >= $1,000/yr), MAYBE, or KEEP. Tool ids: mixpanel, semrush, freshbooks, calendly, chargebee, typeform, pipedrive, gohighlevel, intercom. GET: pass each as a query parameter, e.g. mixpanel=300. POST: {\"spend\": {\"mixpanel\": 300}}.\n\nExample: https://saas-bill-cutter.vercel.app/api/calculate?mixpanel=300&calendly=48&intercom=150&hostingPerMonth=20&hourlyRate=50",
        "parameters": [
          {
            "name": "mixpanel",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Mixpanel / Amplitude (swap: PostHog).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Mixpanel / Amplitude (swap: PostHog).",
              "minimum": 0
            }
          },
          {
            "name": "semrush",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Semrush / Ahrefs (swap: OpenSEO).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Semrush / Ahrefs (swap: OpenSEO).",
              "minimum": 0
            }
          },
          {
            "name": "freshbooks",
            "in": "query",
            "required": false,
            "description": "Monthly spend on FreshBooks (swap: Invoice Ninja).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on FreshBooks (swap: Invoice Ninja).",
              "minimum": 0
            }
          },
          {
            "name": "calendly",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Calendly (swap: Cal.diy).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Calendly (swap: Cal.diy).",
              "minimum": 0
            }
          },
          {
            "name": "chargebee",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Chargebee / Stripe Billing add-ons (swap: Autumn).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Chargebee / Stripe Billing add-ons (swap: Autumn).",
              "minimum": 0
            }
          },
          {
            "name": "typeform",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Typeform (swap: Typebot).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Typeform (swap: Typebot).",
              "minimum": 0
            }
          },
          {
            "name": "pipedrive",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Pipedrive / HubSpot Sales (swap: Frappe CRM).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Pipedrive / HubSpot Sales (swap: Frappe CRM).",
              "minimum": 0
            }
          },
          {
            "name": "gohighlevel",
            "in": "query",
            "required": false,
            "description": "Monthly spend on GoHighLevel / ActiveCampaign (swap: Mautic).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on GoHighLevel / ActiveCampaign (swap: Mautic).",
              "minimum": 0
            }
          },
          {
            "name": "intercom",
            "in": "query",
            "required": false,
            "description": "Monthly spend on Intercom / Zendesk (swap: Chatwoot).",
            "schema": {
              "type": "number",
              "description": "Monthly spend on Intercom / Zendesk (swap: Chatwoot).",
              "minimum": 0
            }
          },
          {
            "name": "hostingPerMonth",
            "in": "query",
            "required": false,
            "description": "Estimated monthly server cost to self-host everything selected.",
            "schema": {
              "type": "number",
              "description": "Estimated monthly server cost to self-host everything selected.",
              "default": 20,
              "minimum": 0
            }
          },
          {
            "name": "hourlyRate",
            "in": "query",
            "required": false,
            "description": "Value of an hour of setup time.",
            "schema": {
              "type": "number",
              "description": "Value of an hour of setup time.",
              "default": 50,
              "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": "saasSelfHostSavingsPost",
        "summary": "Should I replace paid SaaS (Mixpanel, Semrush, Calendly, Intercom...) with a self-hosted open-source alternative? Savings and payback (JSON body)",
        "description": "Give monthly spend per tool id. Returns each open-source swap (repo, license, caveat), yearly paid cost, hosting cost, one-time setup hours and cost, first-year and ongoing net savings, break-even months, and a verdict: SWITCH (payback <= 6 months and >= $1,000/yr), MAYBE, or KEEP. Tool ids: mixpanel, semrush, freshbooks, calendly, chargebee, typeform, pipedrive, gohighlevel, intercom. GET: pass each as a query parameter, e.g. mixpanel=300. POST: {\"spend\": {\"mixpanel\": 300}}.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "mixpanel": {
                    "type": "number",
                    "description": "Monthly spend on Mixpanel / Amplitude (swap: PostHog).",
                    "minimum": 0
                  },
                  "semrush": {
                    "type": "number",
                    "description": "Monthly spend on Semrush / Ahrefs (swap: OpenSEO).",
                    "minimum": 0
                  },
                  "freshbooks": {
                    "type": "number",
                    "description": "Monthly spend on FreshBooks (swap: Invoice Ninja).",
                    "minimum": 0
                  },
                  "calendly": {
                    "type": "number",
                    "description": "Monthly spend on Calendly (swap: Cal.diy).",
                    "minimum": 0
                  },
                  "chargebee": {
                    "type": "number",
                    "description": "Monthly spend on Chargebee / Stripe Billing add-ons (swap: Autumn).",
                    "minimum": 0
                  },
                  "typeform": {
                    "type": "number",
                    "description": "Monthly spend on Typeform (swap: Typebot).",
                    "minimum": 0
                  },
                  "pipedrive": {
                    "type": "number",
                    "description": "Monthly spend on Pipedrive / HubSpot Sales (swap: Frappe CRM).",
                    "minimum": 0
                  },
                  "gohighlevel": {
                    "type": "number",
                    "description": "Monthly spend on GoHighLevel / ActiveCampaign (swap: Mautic).",
                    "minimum": 0
                  },
                  "intercom": {
                    "type": "number",
                    "description": "Monthly spend on Intercom / Zendesk (swap: Chatwoot).",
                    "minimum": 0
                  },
                  "spend": {
                    "type": "object",
                    "description": "POST alternative: object mapping tool id to monthly spend, e.g. {\"mixpanel\": 300}."
                  },
                  "hostingPerMonth": {
                    "type": "number",
                    "description": "Estimated monthly server cost to self-host everything selected.",
                    "default": 20,
                    "minimum": 0
                  },
                  "hourlyRate": {
                    "type": "number",
                    "description": "Value of an hour of setup time.",
                    "default": 50,
                    "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/tools": {
      "get": {
        "operationId": "listOpenSourceSwaps",
        "summary": "List the paid SaaS tools covered and their open-source alternatives, licenses, effort, and caveats",
        "description": "Returns every supported tool id with the paid product, category, open-source swap, GitHub repo, license notes, setup effort (1-3), and the main catch.\n\nExample: https://saas-bill-cutter.vercel.app/api/tools",
        "parameters": [],
        "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": "listOpenSourceSwapsPost",
        "summary": "List the paid SaaS tools covered and their open-source alternatives, licenses, effort, and caveats (JSON body)",
        "description": "Returns every supported tool id with the paid product, category, open-source swap, GitHub repo, license notes, setup effort (1-3), and the main catch.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {}
              }
            }
          }
        },
        "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."
          }
        }
      }
    }
  }
}