{
  "openapi": "3.1.2",
  "info": {
    "title": "RestaurantDoctorAI free tools API",
    "version": "1.14.0",
    "description": "RestaurantDoctorAI's free restaurant tools as a web API: the profit check, recipe costing, the calculators, the deadline calendar and the sourced library. POST a JSON body to a tool's endpoint. No key; nothing sent is stored. The same tools are an MCP server at https://restaurantdoctorai.com/api/mcp. Running a tool is limited to 60 calls a minute from one address. The website check is on the MCP server only.",
    "termsOfService": "https://restaurantdoctorai.com/terms",
    "contact": {
      "email": "support@restaurantdoctorai.com",
      "url": "https://restaurantdoctorai.com/support"
    }
  },
  "externalDocs": {
    "url": "https://restaurantdoctorai.com/ai-assistants#web-api"
  },
  "servers": [
    {
      "url": "https://restaurantdoctorai.com"
    }
  ],
  "security": [],
  "paths": {
    "/api/tools": {
      "get": {
        "operationId": "list_tools",
        "summary": "List the tools",
        "description": "Every tool with its endpoint, an example body and its input schema.",
        "responses": {
          "200": {
            "description": "The tools.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolList"
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_get_questions": {
      "get": {
        "operationId": "describe_restaurantdoctor_get_questions",
        "summary": "Describe: Profit check questions",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_get_questions",
        "summary": "Profit check questions",
        "description": "Lists the 12 multiple-choice questions of the free restaurant profit check, with the answer values each one accepts. Money ranges, delivery apps and review sites follow the restaurant's country (default US).",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "country": {
                    "description": "Where the restaurant is: a two-letter ISO 3166-1 code such as US, CA, AU or DE (GB for the United Kingdom). Sets the currency and local wording. Defaults to US.",
                    "default": "US",
                    "type": "string",
                    "pattern": "^[A-Za-z]{2}$"
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "country": "us"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_run_free_check": {
      "get": {
        "operationId": "describe_restaurantdoctor_run_free_check",
        "summary": "Describe: Run the free profit check",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_run_free_check",
        "summary": "Run the free profit check",
        "description": "Scores a restaurant's 12 answers against RestaurantDoctorAI's targets for its type of restaurant and returns the free result the website shows: an overall grade, grades by area, the estimated money lost to avoidable costs, all of them together, a month and a year, the costliest issue or biggest opportunity with its estimated money a month, what one point of prime cost is worth, and the first fix. Includes a link that opens the same result on restaurantdoctorai.com. Takes only the 12 answers and the country, each answer one of the values its question accepts. The answers aren't stored; only an anonymous daily count of checks is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "serviceModel": {
                    "type": "string",
                    "enum": [
                      "quick_service",
                      "fast_casual",
                      "full_service",
                      "fine_dining",
                      "bar_lounge",
                      "cafe"
                    ],
                    "description": "What kind of restaurant do you run? quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                  },
                  "monthlyRevenue": {
                    "type": "string",
                    "enum": [
                      "under_25k",
                      "25k_60k",
                      "60k_120k",
                      "120k_200k",
                      "over_200k"
                    ],
                    "description": "About how much do you sell in a typical month? Amounts are in US dollars, or in the local currency where that's the euro, pound sterling, Swiss franc, or Canadian, Australian or New Zealand dollar. under_25k = Under $25,000 (Under $300K a year); 25k_60k = $25,000 – $60,000 ($300K – $720K a year); 60k_120k = $60,000 – $120,000 ($720K – $1.44M a year); 120k_200k = $120,000 – $200,000 ($1.44M – $2.4M a year); over_200k = Over $200,000 (Over $2.4M a year)."
                  },
                  "primeCostAwareness": {
                    "type": "string",
                    "enum": [
                      "under_58",
                      "58_to_64",
                      "over_65",
                      "not_tracked_weekly"
                    ],
                    "description": "What's your prime cost: food, drink and labor costs as a share of sales? under_58 = Under 58%; 58_to_64 = 58% – 64%; over_65 = 65% or more; not_tracked_weekly = I don't track it regularly."
                  },
                  "plateCostingFrequency": {
                    "type": "string",
                    "enum": [
                      "live_monthly_software",
                      "6_to_12m_manual",
                      "new_menu_only",
                      "rarely_gut_feeling"
                    ],
                    "description": "How often do you update recipe costs with current supplier prices? live_monthly_software = Monthly or live, with software (Synced to supplier invoices); 6_to_12m_manual = Once or twice a year (In a spreadsheet); new_menu_only = Only when the menu changes; rarely_gut_feeling = Rarely (Prices are set by feel or by competitors)."
                  },
                  "wasteTrackingMethod": {
                    "type": "string",
                    "enum": [
                      "daily_signed_log",
                      "weekly_visual_estimate",
                      "bulk_loss_only",
                      "no_formal_logging"
                    ],
                    "description": "How do you track kitchen waste and spoilage? daily_signed_log = A daily log the chef signs off; weekly_visual_estimate = A rough estimate during weekly inventory; bulk_loss_only = Only when a big batch or case goes bad; no_formal_logging = We don't track it."
                  },
                  "beverageMonitoring": {
                    "type": "string",
                    "enum": [
                      "no_alcohol",
                      "measured_pour_keg_audits",
                      "occasional_spot_checks",
                      "free_pour_no_audit"
                    ],
                    "description": "How do you control drink pours? no_alcohol = We don't serve alcohol; measured_pour_keg_audits = Measured pours, plus weekly pour-cost checks; occasional_spot_checks = Spot checks when bottles run out early; free_pour_no_audit = Free pours, no pour-cost checks."
                  },
                  "laborFlexing": {
                    "type": "string",
                    "enum": [
                      "realtime_cuts_splh",
                      "fixed_shifts_regardless",
                      "overtime_above_8_percent",
                      "chronic_understaffing_owner_covers"
                    ],
                    "description": "When a shift gets slow, what happens to staffing? realtime_cuts_splh = We cut staff based on sales per labor hour; fixed_shifts_regardless = Everyone works their scheduled shift anyway; overtime_above_8_percent = Overtime is common (More than 8% of hours); chronic_understaffing_owner_covers = We're short-staffed (The owner or GM works the line)."
                  },
                  "occupancyCostRatio": {
                    "type": "string",
                    "enum": [
                      "under_8_percent",
                      "8_to_12_percent",
                      "over_12_percent",
                      "unsure_ratio"
                    ],
                    "description": "What share of sales goes to rent, property costs and utilities? under_8_percent = Under 8%; 8_to_12_percent = 8% – 12%; over_12_percent = More than 12%; unsure_ratio = I'm not sure."
                  },
                  "deliveryDependency": {
                    "type": "string",
                    "enum": [
                      "zero_direct_only",
                      "under_15_with_markup",
                      "15_to_35_standard_cut",
                      "over_35_heavy_drag"
                    ],
                    "description": "How much of your sales come through DoorDash, Uber Eats or similar apps? zero_direct_only = None (Dine-in and our own ordering only); under_15_with_markup = Under 15% (With higher app prices to cover fees); 15_to_35_standard_cut = 15% – 35% (At regular menu prices); over_35_heavy_drag = More than 35%."
                  },
                  "seatingDynamics": {
                    "type": "string",
                    "enum": [
                      "consistent_weekround",
                      "packed_weekends_dead_midweek",
                      "strong_lunch_weak_dinner",
                      "erratic_unpredictable"
                    ],
                    "description": "How full is your dining room across the week? consistent_weekround = Steady all week; packed_weekends_dead_midweek = Packed on weekends, quiet midweek; strong_lunch_weak_dinner = Busy lunches, slow dinners; erratic_unpredictable = Hard to predict week to week."
                  },
                  "contactCapture": {
                    "type": "string",
                    "enum": [
                      "automated_pos_loyalty_50plus",
                      "occasional_checkout_emails",
                      "no_database_social_only",
                      "paid_ads_no_list"
                    ],
                    "description": "How do you bring guests back? automated_pos_loyalty_50plus = Loyalty or email list with automatic campaigns (50+ new contacts a week); occasional_checkout_emails = We collect some emails but rarely use them; no_database_social_only = Social media and walk-ins only; paid_ads_no_list = Paid ads, but no guest list of our own."
                  },
                  "reputationHealth": {
                    "type": "string",
                    "enum": [
                      "4_5_to_5_0",
                      "4_0_to_4_4",
                      "3_5_to_3_9",
                      "under_3_5"
                    ],
                    "description": "What's your average rating on Google and Yelp? 4_5_to_5_0 = 4.5 – 5.0 stars; 4_0_to_4_4 = 4.0 – 4.4 stars; 3_5_to_3_9 = 3.5 – 3.9 stars; under_3_5 = Below 3.5 stars."
                  },
                  "country": {
                    "description": "Where the restaurant is: a two-letter ISO 3166-1 code such as US, CA, AU or DE (GB for the United Kingdom). Sets the currency and local wording. Defaults to US.",
                    "default": "US",
                    "type": "string",
                    "pattern": "^[A-Za-z]{2}$"
                  }
                },
                "required": [
                  "serviceModel",
                  "monthlyRevenue",
                  "primeCostAwareness",
                  "plateCostingFrequency",
                  "wasteTrackingMethod",
                  "beverageMonitoring",
                  "laborFlexing",
                  "occupancyCostRatio",
                  "deliveryDependency",
                  "seatingDynamics",
                  "contactCapture",
                  "reputationHealth"
                ],
                "additionalProperties": false
              },
              "example": {
                "serviceModel": "full_service",
                "monthlyRevenue": "60k_120k",
                "primeCostAwareness": "not_tracked_weekly",
                "plateCostingFrequency": "new_menu_only",
                "wasteTrackingMethod": "bulk_loss_only",
                "beverageMonitoring": "occasional_spot_checks",
                "laborFlexing": "fixed_shifts_regardless",
                "occupancyCostRatio": "8_to_12_percent",
                "deliveryDependency": "zero_direct_only",
                "seatingDynamics": "packed_weekends_dead_midweek",
                "contactCapture": "occasional_checkout_emails",
                "reputationHealth": "4_0_to_4_4",
                "country": "us"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_cost_recipe": {
      "get": {
        "operationId": "describe_restaurantdoctor_cost_recipe",
        "summary": "Describe: Cost a recipe (draft)",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_cost_recipe",
        "summary": "Cost a recipe (draft)",
        "description": "Reads a recipe's ingredient lines as written, weighs each one with USDA FoodData Central and USDA yields, and prices it with the owner's own prices when given, else dated US public prices (BLS and USDA ERS store averages, USDA wholesale prices, and USDA weekly store-ad sale prices, which run low). Returns a draft in US dollars: each line's grams, cost and price source, what each line still needs, the cost per plate as a range, and a link that opens the draft on restaurantdoctorai.com, where the owner checks each line and adds prices for one plate cost and a menu price. The draft never gives one plate cost or a menu price, and says nothing about allergens or nutrition. The recipe isn't stored; only an anonymous daily count of drafts is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipe": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 8000,
                    "description": "The recipe as written: its name, its servings line (\"Serves 6\") and its ingredient lines, one a line, each amount and unit exactly as the recipe or the photo gives it. Method steps may follow under a heading such as \"Instructions\"; only ingredient lines are costed. The lines are read as sent, not converted, rounded or corrected: the owner checks them on the website. At most 8000 characters and 60 ingredient lines."
                  },
                  "servings": {
                    "description": "How many plates the recipe makes, when its text doesn't say.",
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 100000
                  },
                  "source": {
                    "default": "text",
                    "description": "Where the recipe came from: text the owner typed or pasted (text), a photo or scan of a printed or typed page (typed-photo), a handwritten card (handwriting), or a PDF (pdf). It sets how many lines the owner confirms on the website: handwriting, every line.",
                    "type": "string",
                    "enum": [
                      "text",
                      "typed-photo",
                      "handwriting",
                      "pdf"
                    ]
                  },
                  "prices": {
                    "description": "The owner's own prices, when they give them. Lines without one use US public prices: store averages (BLS, USDA ERS), wholesale prices (USDA) and, for items those don't cover, USDA weekly store-ad sale prices, which run low. None is the owner's cost. Tap water is costed at 0.",
                    "maxItems": 60,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "ingredient": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100,
                          "description": "The ingredient as the recipe names it, such as \"ground beef\"."
                        },
                        "paid": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1000000,
                          "description": "What the owner pays for one pack, in US dollars."
                        },
                        "packSize": {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 1000000,
                          "description": "How much one pack holds: 10 for a 10 lb case."
                        },
                        "packUnit": {
                          "type": "string",
                          "enum": [
                            "g",
                            "kg",
                            "oz",
                            "lb",
                            "ml",
                            "l",
                            "floz",
                            "gal",
                            "each"
                          ],
                          "description": "The pack's unit: g, kg, oz, lb, ml, l, floz (US fluid ounces), gal (US gallons) or each."
                        },
                        "countOf": {
                          "description": "With packUnit each: what one item is, when it isn't a whole one, such as clove or bunch.",
                          "type": "string",
                          "enum": [
                            "each",
                            "clove",
                            "slice",
                            "stick",
                            "bunch",
                            "sprig",
                            "leaf",
                            "can",
                            "package"
                          ]
                        }
                      },
                      "required": [
                        "ingredient",
                        "paid",
                        "packSize",
                        "packUnit"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "recipe"
                ],
                "additionalProperties": false
              },
              "example": {
                "recipe": "Tomato soup\nServes 4\n2 lb tomatoes\n1 onion\n2 tbsp olive oil\n4 cups vegetable stock"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_deadlines": {
      "get": {
        "operationId": "describe_restaurantdoctor_deadlines",
        "summary": "Describe: List a restaurant's deadlines",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_deadlines",
        "summary": "List a restaurant's deadlines",
        "description": "Lists a US restaurant's coming tax, payroll, license and permit deadlines, as the deadline calendar on restaurantdoctorai.com does: federal dates (payroll forms, tip reports, W-2s, 1099s, returns, estimated tax) and the state's (sales tax, unemployment reports, yearly reports, franchise taxes, minimum wage changes, liquor and health permit dates where one date applies to everyone), each moved for weekends and holidays by the agency's rule, with the rule, what a miss costs and the official source. A state date is given only where the state's own page confirms it; the rest come as what to check with the agency. Also the rules for each hire, and a link that opens the same calendar on the website, where the owner adds their own license and permit dates and gets free email reminders. Takes the state and yes/no answers, no names or emails; scope (federal or state) and withinDays (the next so many days) cut the list. Reminders, not legal or tax advice. The answers aren't stored; only an anonymous daily count of calendars is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "state": {
                    "type": "string",
                    "enum": [
                      "AL",
                      "AK",
                      "AZ",
                      "AR",
                      "CA",
                      "CO",
                      "CT",
                      "DE",
                      "DC",
                      "FL",
                      "GA",
                      "HI",
                      "ID",
                      "IL",
                      "IN",
                      "IA",
                      "KS",
                      "KY",
                      "LA",
                      "ME",
                      "MD",
                      "MA",
                      "MI",
                      "MN",
                      "MS",
                      "MO",
                      "MT",
                      "NE",
                      "NV",
                      "NH",
                      "NJ",
                      "NM",
                      "NY",
                      "NC",
                      "ND",
                      "OH",
                      "OK",
                      "OR",
                      "PA",
                      "RI",
                      "SC",
                      "SD",
                      "TN",
                      "TX",
                      "UT",
                      "VT",
                      "VA",
                      "WA",
                      "WV",
                      "WI",
                      "WY"
                    ],
                    "description": "The restaurant's US state, two letters (DC for Washington DC)."
                  },
                  "staff": {
                    "type": "boolean",
                    "description": "Has anyone on payroll."
                  },
                  "tips": {
                    "default": false,
                    "type": "boolean",
                    "description": "Customers usually tip the staff."
                  },
                  "alcohol": {
                    "type": "boolean",
                    "description": "Sells alcohol."
                  },
                  "business": {
                    "description": "How the business is set up: sole (sole owner, no LLC), llc_single, llc_multi, partnership (no LLC), s_corp or c_corp. Decides the tax return and the state's yearly report. Left out, both return dates come with an \"If\".",
                    "type": "string",
                    "enum": [
                      "sole",
                      "llc_single",
                      "llc_multi",
                      "partnership",
                      "s_corp",
                      "c_corp"
                    ]
                  },
                  "formed": {
                    "description": "The month the LLC or corporation was formed with the state, YYYY-MM. Some states set the yearly report by it.",
                    "type": "string",
                    "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
                  },
                  "salesTax": {
                    "description": "How often the state has the restaurant file sales tax (on its permit letter or state account).",
                    "type": "string",
                    "enum": [
                      "monthly",
                      "quarterly",
                      "yearly"
                    ]
                  },
                  "deposits": {
                    "description": "Who pays the payroll taxes to the IRS: provider (a payroll company), monthly (the owner, by the 15th), semiweekly (the owner, after each payday).",
                    "type": "string",
                    "enum": [
                      "provider",
                      "monthly",
                      "semiweekly"
                    ]
                  },
                  "contractors": {
                    "type": "boolean",
                    "description": "Pays a contractor, or rent to a landlord that isn't a corporation, $2,000 or more a year (1099 forms)."
                  },
                  "estimated": {
                    "type": "boolean",
                    "description": "The owner pays quarterly estimated tax on the business's profit."
                  },
                  "bigTipped": {
                    "type": "boolean",
                    "description": "Tipped, and staff worked more than 80 hours in total on a typical day last year, all locations together (Form 8027)."
                  },
                  "fullTime50": {
                    "type": "boolean",
                    "description": "50 or more full-time staff on average, counting part-timers' hours, related businesses together (ACA forms)."
                  },
                  "caterer": {
                    "type": "boolean",
                    "description": "Mainly catering or a food truck, not a restaurant or bar (OSHA's injury log)."
                  },
                  "city": {
                    "description": "A city with its own minimum wage, as an id like los-angeles or chicago; left out, the state's rate applies.",
                    "type": "string",
                    "pattern": "^[a-z0-9-]{1,40}$"
                  },
                  "months": {
                    "default": 3,
                    "description": "How many months ahead to list, 1 to 15 (default 3). The calendar runs to the end of 2027. withinDays, when sent, sets the window instead.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 15
                  },
                  "scope": {
                    "description": "Optional, to cut the list: federal (the IRS's and other federal dates only), state (the state's and the city's only) or all (the default). The rules for each hire are listed either way.",
                    "type": "string",
                    "enum": [
                      "all",
                      "federal",
                      "state"
                    ]
                  },
                  "withinDays": {
                    "description": "Optional: only the dates in the next so many days, 1 to 460, from today in the state (7 for the coming week). Sent, it replaces months.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 460
                  }
                },
                "required": [
                  "state",
                  "staff",
                  "alcohol"
                ],
                "additionalProperties": false
              },
              "example": {
                "state": "TX",
                "staff": true,
                "tips": true,
                "alcohol": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_search_knowledge": {
      "get": {
        "operationId": "describe_restaurantdoctor_search_knowledge",
        "summary": "Describe: Search RestaurantDoctorAI's library",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_search_knowledge",
        "summary": "Search RestaurantDoctorAI's library",
        "description": "Searches RestaurantDoctorAI's sourced library: the website's guides and blog posts, RestaurantDoctorAI's step-by-step fixes, RestaurantDoctorAI's targets by type of restaurant, sourced industry facts, and an expert knowledge base of sourced how-tos, rules and checklists (costs, labor, money, growth, compliance, operations). Keyword search: \"break-even\", \"breakeven\" and \"break even\" are one term, and plurals match. Returns the best passages, each with its id, kind, title, link and source; kind narrows the search to one kind of entry. RestaurantDoctorAI's targets are its own, not industry benchmarks. The query isn't stored; only an anonymous daily count of searches and reads is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "What to look up, in plain words, e.g. 'how to lower food cost', 'tip pool rules' or 'delivery app commission'."
                  },
                  "limit": {
                    "default": 5,
                    "description": "The most passages to return, 1 to 8 (default 5). Up to 5, a passage far weaker than the best match is left out.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 8
                  },
                  "kind": {
                    "description": "Only this kind of entry: guide (the website's guides), post (blog posts), play (RestaurantDoctorAI's step-by-step fixes), targets (RestaurantDoctorAI's targets by type of restaurant), fact (sourced industry facts) or knowledge (sourced how-tos, rules and checklists). Left out, every kind.",
                    "type": "string",
                    "enum": [
                      "guide",
                      "post",
                      "play",
                      "targets",
                      "fact",
                      "knowledge"
                    ]
                  }
                },
                "required": [
                  "query"
                ],
                "additionalProperties": false
              },
              "example": {
                "query": "prime cost target for a cafe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_list_knowledge": {
      "get": {
        "operationId": "describe_restaurantdoctor_list_knowledge",
        "summary": "Describe: List RestaurantDoctorAI's library",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_list_knowledge",
        "summary": "List RestaurantDoctorAI's library",
        "description": "Lists the entries of RestaurantDoctorAI's sourced library, all or one kind (guide, post, play, targets, fact or knowledge), up to 50 at a time: each with its id, kind, title, link and source, and for guides and blog posts the day it was published and last updated. It shows what the library has, such as every blog post and its date. Pages with offset and limit; nextOffset gives the next page. Nothing about the request is stored; only an anonymous daily count of searches (a list counts as one) is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "default": "all",
                    "description": "Which kind of entry to list: guide (the website's guides), post (blog posts), play (RestaurantDoctorAI's step-by-step fixes), targets (RestaurantDoctorAI's targets by type of restaurant), fact (sourced industry facts) or knowledge (sourced how-tos, rules and checklists); or all (the default).",
                    "type": "string",
                    "enum": [
                      "guide",
                      "post",
                      "play",
                      "targets",
                      "fact",
                      "knowledge",
                      "all"
                    ]
                  },
                  "offset": {
                    "default": 0,
                    "description": "How many entries to skip (default 0). The next page starts at the nextOffset the previous list returned.",
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991
                  },
                  "limit": {
                    "default": 20,
                    "description": "How many entries to return, 1 to 50 (default 20).",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 50
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "kind": "guide"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_read_knowledge": {
      "get": {
        "operationId": "describe_restaurantdoctor_read_knowledge",
        "summary": "Describe: Read a library entry",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_read_knowledge",
        "summary": "Read a library entry",
        "description": "Reads one entry of RestaurantDoctorAI's library in full (a guide, a blog post, a playbook fix, the targets, a fact or a knowledge entry), by its id (such as 'guide:restaurant-prime-cost'), with its title, link and source. A long entry comes 8,000 characters at a time, with its total length: the next part starts at the nextOffset it returns. The query isn't stored; only an anonymous daily count of searches and reads is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 120,
                    "description": "An entry id, as the library's search and list give it, e.g. 'guide:restaurant-prime-cost' or 'post:restaurant-break-even-point'."
                  },
                  "offset": {
                    "default": 0,
                    "description": "Where to start, in characters (default 0, the start). A long entry comes 8,000 characters at a time: the next part starts at the nextOffset the previous read returned.",
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991
                  }
                },
                "required": [
                  "id"
                ],
                "additionalProperties": false
              },
              "example": {
                "id": "guide:restaurant-prime-cost"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_prime_cost": {
      "get": {
        "operationId": "describe_restaurantdoctor_prime_cost",
        "summary": "Describe: Prime cost calculator",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_prime_cost",
        "summary": "Prime cost calculator",
        "description": "Works out a restaurant's prime cost from the owner's own figures for one week or month, as the free prime cost calculator on restaurantdoctorai.com does: food and drink used plus labor, as a share of net sales, against the target for its type of restaurant, with what the points over or under are worth, food and labor each against their own range, and which to look at first. Takes net sales, food and drink purchases and wages, plus optional payroll taxes and benefits, stock counts and the owner's unpaid hours, in any currency; a figure that isn't sent is never counted as 0. Returns the calculator's result, how it was worked out, and a link that opens the calculator with the same figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "format": {
                    "type": "string",
                    "enum": [
                      "quick_service",
                      "fast_casual",
                      "full_service",
                      "fine_dining",
                      "bar_lounge",
                      "cafe"
                    ],
                    "description": "The type of restaurant, which sets the targets: prime cost, and the ranges for food and drink and for labor: quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                  },
                  "period": {
                    "type": "string",
                    "enum": [
                      "week",
                      "month"
                    ],
                    "description": "Whether every figure covers one week or one month, the same dates for all of them. Sets how a year is worked out (52 weeks or 12 months)."
                  },
                  "sales": {
                    "anyOf": [
                      {
                        "description": "Net sales for the period, in the owner's own currency like every figure here, from the POS sales summary: after discounts and comps, before tax and tips, with any service charge paid out to staff added back. Needed for a result, and more than 0; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "purchases": {
                    "anyOf": [
                      {
                        "description": "Food and drink supplier invoices for the same dates, added up by delivery date, minus credits. No packaging. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "wages": {
                    "anyOf": [
                      {
                        "description": "Every wage and salary for the same dates, from payroll, managers included (a salary counts as a 52nd of a year for a week, a 12th for a month). No tips, but a service charge paid to staff stays in. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "payrollCosts": {
                    "anyOf": [
                      {
                        "description": "Optional: the employer's payroll taxes and benefits for the period, such as health insurance or a pension, when the wages figure leaves them out.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "openingStock": {
                    "anyOf": [
                      {
                        "description": "Optional: stock at cost at the start of the period. Used only with closingStock: food and drink then becomes what was used, opening + purchases - closing.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "closingStock": {
                    "anyOf": [
                      {
                        "description": "Optional: stock at cost at the end of the period, counted on the same items the invoices cover. Used only with openingStock.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "ownerPay": {
                    "anyOf": [
                      {
                        "description": "Optional: when the owner works in the restaurant without a salary, what they'd pay someone to do their hours, plus the payroll taxes on it. It's a second figure; the main one stays as the books have it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "format",
                  "period"
                ],
                "additionalProperties": false
              },
              "example": {
                "format": "full_service",
                "period": "week",
                "sales": 20000,
                "purchases": 6400,
                "wages": 6800
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_labor_cost": {
      "get": {
        "operationId": "describe_restaurantdoctor_labor_cost",
        "summary": "Describe: Labor cost calculator",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_labor_cost",
        "summary": "Labor cost calculator",
        "description": "Works out a restaurant's labor cost from the owner's own payroll figures for one week or month, as the free labor cost calculator on restaurantdoctorai.com does, in one of its three modes: share (labor as a % of net sales, against the range for its type of restaurant, with what the points over are worth), hours (next period's labor budget and the hourly staff hours it pays for once salaries are paid) or line (the cut line: the sales per labor hour below which the first person goes home). Takes net sales, hourly pay and hours worked, plus optional salaries, payroll taxes and benefits, expected sales, a target and more, in any currency; a figure that isn't sent is never counted as 0. Returns the calculator's result, how it was worked out, and a link that opens the calculator with the same figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "share",
                      "hours",
                      "line"
                    ],
                    "description": "What to work out, as the page's tabs. share: last period's labor cost, % of net sales, against the range (needs sales, hourlyWages). hours: the labor budget for next period's expected sales and the hourly staff hours it pays for (needs forecast, hourlyWages, hours). line: the cut line, the sales per labor hour below which the first person goes home (needs hourlyWages, hours, and sales or forecast)."
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "quick_service",
                      "fast_casual",
                      "full_service",
                      "fine_dining",
                      "bar_lounge",
                      "cafe"
                    ],
                    "description": "The type of restaurant, which sets the labor range and the starting target: quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                  },
                  "period": {
                    "type": "string",
                    "enum": [
                      "week",
                      "month"
                    ],
                    "description": "Whether the figures are a week's or a month's: last period's, all for the same dates, and forecast for the next. Sets how a year is worked out (52 weeks or 12 months)."
                  },
                  "sales": {
                    "anyOf": [
                      {
                        "description": "Last period's net sales, in the owner's own currency like every amount here, from the POS: after discounts and comps, before tax and tips, plus any service charge paid out to staff. Needed for share, and for line without forecast.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hourlyWages": {
                    "anyOf": [
                      {
                        "description": "Last period's gross pay for everyone paid by the hour, from payroll: by the days worked, overtime in, tips out. 0 if all are salaried (share only). Needed in every mode.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hours": {
                    "anyOf": [
                      {
                        "description": "Hours those staff worked last period, from the time clock: overtime in, salaried managers out. Needed for hours and line.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "salaries": {
                    "anyOf": [
                      {
                        "description": "Optional: salaried pay for the period (a yearly salary ÷ 52, or ÷ 12 for a month).",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "payrollCosts": {
                    "anyOf": [
                      {
                        "description": "Optional: the employer's payroll taxes and benefits on that pay, such as health insurance. Left out, labor reads lower, unless the pay already includes them.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "overtimeHours": {
                    "anyOf": [
                      {
                        "description": "Optional, for share: how many of the hours worked were overtime.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "ownerPay": {
                    "anyOf": [
                      {
                        "description": "Optional, for share: if the owner works without a salary, what someone doing their hours would cost, payroll taxes in. Shown as a second figure.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "forecast": {
                    "anyOf": [
                      {
                        "description": "Net sales expected next period, more than 0: the last 4 weeks' (or 3 months') average, adjusted for events and holidays. Needed for hours; for line, the line is then for these sales.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "target": {
                    "anyOf": [
                      {
                        "description": "Optional, for hours and line: the owner's labor target, % of net sales (1 to 99). Left out: the top of the range, where the page starts.",
                        "type": "number",
                        "minimum": 1,
                        "maximum": 99
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hourSales": {
                    "anyOf": [
                      {
                        "description": "Optional, for line: net sales in the last hour of a shift, for how many hourly staff it pays for.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "mode",
                  "format",
                  "period"
                ],
                "additionalProperties": false
              },
              "example": {
                "mode": "share",
                "format": "full_service",
                "period": "week",
                "sales": 22500,
                "hourlyWages": 5175,
                "hours": 345,
                "salaries": 1800,
                "payrollCosts": 900
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_break_even": {
      "get": {
        "operationId": "describe_restaurantdoctor_break_even",
        "summary": "Describe: Break-even calculator",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_break_even",
        "summary": "Break-even calculator",
        "description": "Works out a restaurant's break-even sales from the owner's figures for one typical month, as the free break-even calculator on restaurantdoctorai.com does: the sales a month needs to pay every bill, also a week, a day open and guests a day; how far the month was above or short of it; what was left over after every bill; what a point of cost moves it by; with and without the owner's own pay; and if prices were 10% lower or higher (an illustration). Hourly pay can rise with sales or stay fixed, or both ways as a range. Takes the month's figures in any currency; a figure not sent is never counted as 0. Returns the result, the working and a link that opens the calculator with the figures in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sales": {
                    "anyOf": [
                      {
                        "description": "Net sales for one typical month, in the owner's own currency: the POS sales summary, before tax and tips, app orders at menu price. Not a holiday rush: every figure is for that month. Needed, more than 0; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "purchases": {
                    "anyOf": [
                      {
                        "description": "That month's food and drink supplier invoices, by delivery date. Needed; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hourlyPay": {
                    "anyOf": [
                      {
                        "description": "That month's hourly wages from payroll, plus the employer's payroll taxes and benefits; no tips. Paid every two weeks: one pay run × 26 ÷ 12. Needed (0 with no hourly staff); if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "otherVariable": {
                    "anyOf": [
                      {
                        "description": "That month's other costs that rise with every sale: card fees, app commissions (app sales minus payouts, without tax and tips), packaging, percentage rent, royalties, ad fund fees; nothing in the food and drink invoices. Needed (0 if none); if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hourly": {
                    "default": "unsure",
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "yes",
                          "no",
                          "unsure"
                        ],
                        "description": "Whether hourly staff time goes up and down with sales: yes, shifts are added and cut as it gets busy or quiet; no, about the same team every shift (a bill that stays the same); unsure (the default): both ways, as a range."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fixedBills": {
                    "anyOf": [
                      {
                        "description": "A month of the bills that stay the same: rent and utilities, salaries with their payroll taxes and benefits, insurance, software, marketing, loan and lease payments in full. No depreciation. Yearly bills ÷ 12. Not the owner's pay. Needed; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "ownerPay": {
                    "anyOf": [
                      {
                        "description": "Optional: the owner's own pay a month, if not on payroll. Counted as a bill; break-even is also given without it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "averageSpend": {
                    "anyOf": [
                      {
                        "description": "Optional: average spend per guest, the POS average check or net sales ÷ guests. Turns sales into guests.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "daysPerWeek": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 7,
                        "description": "Optional: days open a week, a whole number from 1 to 7. Turns the month into a day open (and guests a day, with averageSpend)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "openingStock": {
                    "anyOf": [
                      {
                        "description": "Optional: stock at cost at the start of the month. Used only with closingStock: food and drink is then opening + purchases - closing. Skip both if stock stayed steady.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "closingStock": {
                    "anyOf": [
                      {
                        "description": "Optional: stock at cost at the end of the month. Used only with openingStock.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "goal": {
                    "anyOf": [
                      {
                        "description": "Optional: what the owner would like left over a month after every bill, before income tax. Adds the sales for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "sales": 90000,
                "purchases": 28800,
                "hourlyPay": 22500,
                "otherVariable": 4950,
                "hourly": "unsure",
                "fixedBills": 21400,
                "ownerPay": 5000,
                "averageSpend": 45,
                "daysPerWeek": 6
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_restaurant_budget": {
      "get": {
        "operationId": "describe_restaurantdoctor_restaurant_budget",
        "summary": "Describe: Restaurant budget calculator",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_restaurant_budget",
        "summary": "Restaurant budget calculator",
        "description": "Works out a restaurant's monthly budget from the owner's expected sales and type of restaurant, as the free restaurant budget calculator on restaurantdoctorai.com does: food and drink, labor, prime cost and rent with utilities as money ranges by RestaurantDoctorAI's targets for that type, other operating costs at the owner's share or a 20% working assumption, what's left after every bill, and break-even sales with labor counted both ways. Takes expected net sales and the type, plus optional rent, the owner's own pay and the other costs share, in any currency; a figure that isn't sent is never counted as 0. Returns the calculator's result, how it was worked out, and a link that opens the calculator with the same figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "format": {
                    "type": "string",
                    "enum": [
                      "quick_service",
                      "fast_casual",
                      "full_service",
                      "fine_dining",
                      "bar_lounge",
                      "cafe"
                    ],
                    "description": "The type of restaurant, which sets RestaurantDoctorAI's targets the budget is split by: quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                  },
                  "sales": {
                    "anyOf": [
                      {
                        "description": "Expected net sales for one month, in the owner's own currency like every figure here: before tax and tips. Needed for a result, and more than 0; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "rent": {
                    "anyOf": [
                      {
                        "description": "Optional: the owner's own rent, property charges and utilities for a month, together, as the occupancy targets count them. Replaces the occupancy range.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "ownerPay": {
                    "anyOf": [
                      {
                        "description": "Optional: the owner's own pay for a month, when it isn't on payroll. Comes off what's left, and counts as a bill that stays the same.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "otherPct": {
                    "anyOf": [
                      {
                        "description": "Optional: other operating costs as a % of sales (card fees, packaging, cleaning, repairs, marketing, insurance, software, accounting, loan payments). Left out, 20% is used: a working assumption, not a target or a published figure.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 60
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "format"
                ],
                "additionalProperties": false
              },
              "example": {
                "format": "full_service",
                "sales": 90000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_plate_cost": {
      "get": {
        "operationId": "describe_restaurantdoctor_plate_cost",
        "summary": "Describe: Plate cost and menu price calculator",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_plate_cost",
        "summary": "Plate cost and menu price calculator",
        "description": "Works out what one plate of a dish costs and what to charge for it, as the free plate cost calculator on restaurantdoctorai.com does: from each ingredient's pack price and the amount used (with a usable % for trim), or from a plate cost the owner already knows; then the food cost at the menu price, what's left per plate, the price for their target food cost and the prices inside the range for their type of restaurant, with the tax taken out of a tax-inclusive menu. It works from the owner's own prices and amounts, in any currency; a figure that isn't sent is never counted as 0. Returns the calculator's result, how it was worked out, and a link that opens the calculator with the same figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "ingredients",
                      "known"
                    ],
                    "description": "ingredients: from each ingredient's pack price and the amount used. known: from a plate cost the owner already has."
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "quick_service",
                      "fast_casual",
                      "full_service",
                      "fine_dining",
                      "bar_lounge",
                      "cafe"
                    ],
                    "description": "The type of restaurant, which sets the food cost range and the starting target: quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                  },
                  "ingredients": {
                    "anyOf": [
                      {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "anyOf": [
                                {
                                  "description": "Optional: what it is, as the owner calls it.",
                                  "type": "string",
                                  "maxLength": 100
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "paid": {
                              "anyOf": [
                                {
                                  "description": "What the owner paid for one pack, from their latest invoice, before any VAT or GST they claim back.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "packSize": {
                              "anyOf": [
                                {
                                  "description": "How much one pack holds, in packUnit: 5 for a 5 lb bag. A case of 6 cans is 6 each; a 4 × 5 lb case is 20 lb.",
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "packUnit": {
                              "type": "string",
                              "enum": [
                                "g",
                                "kg",
                                "oz",
                                "lb",
                                "ml",
                                "l",
                                "floz",
                                "gal",
                                "each"
                              ],
                              "description": "The pack's unit: floz and gal are US fluid ounces and gallons."
                            },
                            "used": {
                              "anyOf": [
                                {
                                  "description": "The amount that goes in the pot or on the plate, after trimming, for the plates in portions. Spoons or cups: weighed once.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "usedUnit": {
                              "type": "string",
                              "enum": [
                                "g",
                                "kg",
                                "oz",
                                "lb",
                                "ml",
                                "l",
                                "floz",
                                "gal",
                                "each"
                              ],
                              "description": "The amount's unit, of the pack's kind: weight, volume and count don't convert into each other."
                            },
                            "usable": {
                              "anyOf": [
                                {
                                  "description": "Optional: of what's bought, the % left after trimming or cooking: 85 for 1 kg that trims to 850 g. Left out, 100.",
                                  "type": "number",
                                  "minimum": 1,
                                  "maximum": 100
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          },
                          "required": [
                            "packUnit",
                            "usedUnit"
                          ],
                          "additionalProperties": false
                        },
                        "description": "With mode ingredients: each ingredient. A sauce or side already costed is one: its cost for a pack of 1 each, 1 each used."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "portions": {
                    "anyOf": [
                      {
                        "description": "With mode ingredients, needed: how many plates the amounts make, 1 for a single plate.",
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "extras": {
                    "anyOf": [
                      {
                        "description": "Optional, mode ingredients: small extras without a line of their own (salt, oil, garnish), % of the ingredients; often 5 to 10.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "plateCost": {
                    "anyOf": [
                      {
                        "description": "With mode known, needed: what the ingredients on one plate cost, from a recipe card or costing sheet, in the owner's own currency like every money figure here.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "menuPrice": {
                    "anyOf": [
                      {
                        "description": "Optional: the dish's price on the menu. Left out, the result gives the prices to charge, as for a new dish.",
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "taxIncluded": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "true when menu prices include VAT or GST (UK, EU, Australia, New Zealand); left out when tax is added at the till (US, Canada)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "taxRate": {
                    "anyOf": [
                      {
                        "description": "With taxIncluded, needed: the tax rate in this dish's price, %. Food and drinks can have different rates.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 50
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "target": {
                    "anyOf": [
                      {
                        "description": "Optional: the owner's target food cost, %. Left out, the middle of the format's range (32 for full service); none for a bar.",
                        "type": "number",
                        "minimum": 1,
                        "maximum": 99
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "sold": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 1000000000,
                        "description": "Optional: how many of this dish sold last month (POS item sales), for the figures a month."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "mode",
                  "format"
                ],
                "additionalProperties": false
              },
              "example": {
                "mode": "ingredients",
                "format": "full_service",
                "ingredients": [
                  {
                    "name": "Ground beef",
                    "paid": 28,
                    "packSize": 5,
                    "packUnit": "lb",
                    "used": 6,
                    "usedUnit": "oz"
                  },
                  {
                    "name": "Bun, cheese, toppings and fries",
                    "paid": 2.1,
                    "packSize": 1,
                    "packUnit": "each",
                    "used": 1,
                    "usedUnit": "each"
                  }
                ],
                "portions": 1,
                "menuPrice": 14
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_delivery_price": {
      "get": {
        "operationId": "describe_restaurantdoctor_delivery_price",
        "summary": "Describe: Delivery app price calculator",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_delivery_price",
        "summary": "Delivery app price calculator",
        "description": "Works out a dish's break-even price on a delivery app, the app price that leaves the owner the same money as selling it in their dining room, as the free delivery app price calculator on restaurantdoctorai.com does: the in-house price ÷ (1 − the app's real commission rate), the markup on the in-house price that takes (rounded up to a whole percent), and what the app keeps. Takes the dish's in-house price, in any currency, and one app's real commission rate from its payout statements; a figure that isn't sent is never counted as 0. Returns the calculator's result, how it was worked out, and a link that opens the calculator with the same figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "price": {
                    "anyOf": [
                      {
                        "description": "The dish's price on the owner's own menu, as a dining room guest pays it, in the owner's own currency (14 or 18.5). Needed for a result, and more than 0; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "rate": {
                    "anyOf": [
                      {
                        "description": "One delivery app's real commission rate, as a percent: 30 for 30%, not 0.30. From a month of that app's payout statements: (menu sales before tax and tips − the app's payout without tax and tips) ÷ those menu sales × 100, so marketing fees, promotions the owner funds and refunds are in it; the rate in the app's plan leaves them out. Each app is worked out on its own. Needed for a result: 0, or from 1 to 89; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 89
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "price": 14,
                "rate": 30
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_menu_calories": {
      "get": {
        "operationId": "describe_restaurantdoctor_menu_calories",
        "summary": "Describe: Menu calorie counter",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_menu_calories",
        "summary": "Menu calorie counter",
        "description": "Works out a dish's calories from its recipe, as the free menu calorie counter on restaurantdoctorai.com does: each ingredient's calories from USDA FoodData Central (a list of 118 common foods) or its pack label, added up, shared by the plates it makes or by portion weight, and rounded once the way US, Ontario or UK and EU menus show calories. Ingredients are matched to that list, never guessed: words that fit several foods come back with the foods to pick from, and words that fit none with the nearest foods, or as not on the list. A pack label's kcal per 100 g comes from the owner's own label, never an estimate: without one, that ingredient can't be counted yet. Returns the menu figure, the exact one, how it was worked out with each food's FDC ID, what to check before printing, and a link that opens the counter with the same recipe filled in. It's an estimate, not a lab test. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "country": {
                    "type": "string",
                    "enum": [
                      "us",
                      "ontario",
                      "ukeu"
                    ],
                    "description": "Where the menu is: sets the energy figure and its rounding. us = US; ontario = Canada (Ontario); ukeu = UK, Ireland or EU (kcal, with the EU's energy factors)."
                  },
                  "dish": {
                    "anyOf": [
                      {
                        "description": "Optional: the dish's name, for the record.",
                        "type": "string",
                        "minLength": 0,
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "ingredients": {
                    "anyOf": [
                      {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "food": {
                              "anyOf": [
                                {
                                  "description": "The food: its name on the counter's list of USDA foods, as an earlier answer gave it, or the owner's words for it, matched to that list. Words that fit several foods, or none, come back as a tool error naming the foods to pick from, or saying it isn't on the list. With kcalPer100g, just its name.",
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 100
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "kcalPer100g": {
                              "anyOf": [
                                {
                                  "description": "For a food not on the list: kcal per 100 g from the nutrition panel on the owner's own pack, as the owner reads it (a US label gives a serving: its calories ÷ its grams × 100). It's the label's figure, not an estimate by the assistant: without the owner's label, the ingredient can't be counted yet. Weighed only.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 900
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "amount": {
                              "anyOf": [
                                {
                                  "description": "How much goes in, after trimming, in unit. Weighed if possible. Needed for a result; if missing, the reply asks for it.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "unit": {
                              "type": "string",
                              "enum": [
                                "g",
                                "kg",
                                "oz",
                                "lb",
                                "ml",
                                "l",
                                "floz",
                                "cup",
                                "tbsp",
                                "tsp",
                                "each"
                              ],
                              "description": "g, kg, oz or lb for any food. ml, l, floz, cup, tbsp or tsp (US measures) for liquids and fats only; each for foods counted by the piece."
                            }
                          },
                          "required": [
                            "unit"
                          ],
                          "additionalProperties": false
                        },
                        "description": "What goes into the dish or batch, one entry each. Needed for a result; if missing, the reply asks for it."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "portioning": {
                    "type": "string",
                    "enum": [
                      "plates",
                      "weight"
                    ],
                    "description": "plates: one plate, or a batch shared into plates (12 pancakes). weight: portions weighed from a cooked batch (a ladle of soup)."
                  },
                  "plates": {
                    "anyOf": [
                      {
                        "description": "With plates: how many plates it makes, 1 for a single plate. Needed then; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0.001,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cookedWeight": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "amount": {
                            "type": "number",
                            "minimum": 0.001,
                            "maximum": 1000000000
                          },
                          "unit": {
                            "type": "string",
                            "enum": [
                              "g",
                              "kg",
                              "oz",
                              "lb"
                            ]
                          }
                        },
                        "required": [
                          "amount",
                          "unit"
                        ],
                        "additionalProperties": false,
                        "description": "With weight: the whole batch, weighed after cooking. Needed then; if missing, the reply asks for it."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "portionWeight": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "amount": {
                            "type": "number",
                            "minimum": 0.001,
                            "maximum": 1000000000
                          },
                          "unit": {
                            "type": "string",
                            "enum": [
                              "g",
                              "kg",
                              "oz",
                              "lb"
                            ]
                          }
                        },
                        "required": [
                          "amount",
                          "unit"
                        ],
                        "additionalProperties": false,
                        "description": "With weight: one portion. Needed then; if missing, the reply asks for it."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "country",
                  "portioning"
                ],
                "additionalProperties": false
              },
              "example": {
                "country": "us",
                "dish": "Burger plate",
                "ingredients": [
                  {
                    "food": "Ground beef 80/20, pan-broiled patty",
                    "amount": 124.17,
                    "unit": "g"
                  },
                  {
                    "food": "Burger or hot dog bun",
                    "amount": 1,
                    "unit": "each"
                  },
                  {
                    "food": "Cheddar",
                    "amount": 1,
                    "unit": "each"
                  },
                  {
                    "food": "Ketchup",
                    "amount": 1,
                    "unit": "tbsp"
                  },
                  {
                    "food": "Lettuce, iceberg",
                    "amount": 1,
                    "unit": "each"
                  },
                  {
                    "food": "Tomato, raw",
                    "amount": 1,
                    "unit": "each"
                  }
                ],
                "portioning": "plates",
                "plates": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_fica_tip_credit": {
      "get": {
        "operationId": "describe_restaurantdoctor_fica_tip_credit",
        "summary": "Describe: FICA tip credit check",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_fica_tip_credit",
        "summary": "FICA tip credit check",
        "description": "Estimates a US restaurant's FICA tip credit (IRS Form 8846, the 45B credit) for a year like the one in its payroll figures, as the free FICA tip credit check on restaurantdoctorai.com does: the employer's 7.65% Social Security and Medicare tax on reported tips, less the tips needed to bring tipped staff's cash wage up to the 5.15 dollars an hour the law fixes for restaurants. Returns the reasons the real answer may be zero first (already claimed, no federal income tax owed, service charges aren't tips, only the business can claim it), then the credit as a range, its worth after the deduction it replaces, the years that may still be open, and sources. It answers questions about taxes on tips, Form 8846, the 45B credit or money the business may be missing on tips. It needs the state, a year's tips reported through payroll (never service charges) and, where the cash wage is under 5.15 dollars, tipped staff's hours that year; whether the return already includes Form 8846 comes first, if known. A figure that isn't sent is never counted as 0. It files nothing, isn't tax advice and takes no payment: the result is an estimate to take to the accountant, with a link that opens the same check with the figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "alreadyClaimed": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "yes",
                          "no",
                          "unsure"
                        ],
                        "description": "Optional, asked first: whether the business's return already includes Form 8846 (Form 3800, Part III, line 4f, or the credit on a K-1 from the business): yes, no or unsure (left out: unsure). Yes means there may be nothing left to find."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "state": {
                    "anyOf": [
                      {
                        "description": "The US state the restaurant is in: a two-letter code (TX) or its name. It sets tipped staff's cash wage from the US Department of Labor's table. Needed for a result unless cashWage is sent; if missing, the reply asks for it.",
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cashWage": {
                    "anyOf": [
                      {
                        "description": "Optional: the hourly cash wage tipped staff were paid before tips that year, in US dollars (2.13), if it wasn't the state's tipped wage; the lowest if it changed. Used instead of the state's.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "reportedTips": {
                    "anyOf": [
                      {
                        "description": "A year's tips reported through payroll for one business, in US dollars: line 5b of the year's four Forms 941 added up, W-2 box 7 totals, or the year's total from the payroll tips report (Toast, Gusto). Service charges, automatic gratuities and delivery fees don't count: they're wages. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "tippedHours": {
                    "anyOf": [
                      {
                        "description": "The hours tipped staff worked that year, all together, from the payroll hours report. Needed for a result only when the cash wage is under $5.15 an hour (Texas: $2.13); then, if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "businessType": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "c_corp",
                          "s_corp",
                          "partnership",
                          "sole_owner",
                          "unsure"
                        ],
                        "description": "Optional: how the business files its taxes, which sets what the credit is worth after tax: c_corp = C corporation; s_corp = S corporation (or an LLC taxed as one); partnership = Partnership (or an LLC taxed as one); sole_owner = Sole owner (or a one-owner LLC); unsure = Not sure (left out: unsure)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "owesIncomeTax": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "yes",
                          "no",
                          "unsure"
                        ],
                        "description": "Optional: whether the business (for a pass-through, its owners) usually owes federal income tax: yes, no or unsure (left out: unsure)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "state": "TX",
                "reportedTips": 600000,
                "tippedHours": 22500,
                "businessType": "s_corp"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_card_fees": {
      "get": {
        "operationId": "describe_restaurantdoctor_card_fees",
        "summary": "Describe: Card fees check",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_card_fees",
        "summary": "Card fees check",
        "description": "Checks a US restaurant's card processing fees for one month, as the free card fees check on restaurantdoctorai.com does: the cost per 100 dollars of card sales (the effective rate), against a dated fair range for that type of restaurant (an estimate of a competitive interchange-plus account from Visa's published restaurant interchange, network fees and a fair markup); how far above it the fees are, a month and a year; how they compare with Square's, Toast's, Clover's or Stripe's published rate; what's realistic for that processor, words to read out to it, the fees to question on the statement by name, and the caveats. It answers whether card fees are too high, what the effective rate is, and what to ask the processor. It needs the month's total card sales and total card fees from the processor's statement (every fee, monthly and annual ones included), who processes the cards and what kind of restaurant it is; the number of card sales or the average sale narrows it. A figure that isn't sent is never counted as 0. It doesn't read statements, contact a processor or take payment. Returns the result, how it was worked out, and a link that opens the same check with the figures filled in. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cardSales": {
                    "anyOf": [
                      {
                        "description": "A month's card sales in US dollars, from the processor's statement or the POS card report: everything charged to cards, tips included, before fees, without delivery app orders. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "totalFees": {
                    "anyOf": [
                      {
                        "description": "The same month's total card fees in US dollars, from the same statement: every fee the processor took (percentage, per-sale, monthly, annual, PCI and statement fees), not one line. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "processor": {
                    "type": "string",
                    "enum": [
                      "square",
                      "toast",
                      "clover",
                      "stripe",
                      "bank",
                      "other"
                    ],
                    "description": "Who processes the cards (the name at the top of the statement): bank = a bank or independent processor; other = another processor, or not sure."
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "quick_service",
                      "fast_casual",
                      "full_service",
                      "fine_dining",
                      "bar_lounge",
                      "cafe"
                    ],
                    "description": "The type of restaurant, which sets the likely mix of debit and credit cards: quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                  },
                  "cardCount": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 1000000000,
                        "description": "Optional: the month's number of card sales (transactions), from the same statement. It narrows the fair range to the owner's own sale size."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "averageTicket": {
                    "anyOf": [
                      {
                        "description": "Optional: the average card sale in US dollars, when cardCount isn't known. It narrows the fair range too.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "pricingModel": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "flat",
                          "interchange_plus",
                          "tiered",
                          "not_sure"
                        ],
                        "description": "Optional, if the owner knows it: flat = Flat rate: one rate for every card; interchange_plus = Interchange-plus: interchange at cost plus a stated markup; tiered = Tiered: qualified, mid-qualified and non-qualified rates; not_sure = Not sure. It changes the advice, not the fair range."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "processor",
                  "format"
                ],
                "additionalProperties": false
              },
              "example": {
                "cardSales": 80000,
                "totalFees": 2810,
                "processor": "bank",
                "format": "full_service",
                "averageTicket": 35,
                "pricingModel": "tiered"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_booking_fees": {
      "get": {
        "operationId": "describe_restaurantdoctor_booking_fees",
        "summary": "Describe: Booking fee check",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_booking_fees",
        "summary": "Booking fee check",
        "description": "Works out what a US restaurant's reservation app costs it, as the free booking fee check on restaurantdoctorai.com does: a month, a year, per guest who booked through it and as a share of the average spend, from the plan's published price (dated, sourced) or the owner's invoice, plus fees per guest and the percentage on deposits. Of the apps checked, only OpenTable charges per guest: for guests from its own app and website, possibly from Google and partners, and on Basic from the restaurant's own website. Returns a one-sentence headline first, the month line by line, what isn't counted, what the owner can do (book direct, mark no-shows, the contract's notice date), other apps' published prices as information, not a recommendation, the caveats and sources. It answers what OpenTable, Resy, Tock, Yelp, Toast Tables, SpotOn or SevenRooms costs a restaurant per reservation or per guest. It needs the app and plan (on the invoice) and, for OpenTable, last month's guests from its covers report by where they booked; the rest is optional. A figure that isn't sent is never counted as 0. Not affiliated with any app; it reads no account. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platform": {
                    "type": "string",
                    "enum": [
                      "opentable_basic",
                      "opentable_core",
                      "opentable_pro",
                      "resy_platform",
                      "resy_platform_360",
                      "tock_essential",
                      "tock_premium",
                      "yelp_basic",
                      "yelp_plus",
                      "toast_tables_plus",
                      "spoton_reserve",
                      "sevenrooms",
                      "other"
                    ],
                    "description": "The app and plan, on the invoice. tock_ = Tock, now sold by Resy; other = any app not listed, with monthlyFee."
                  },
                  "networkCovers": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 1000000000,
                        "description": "Guests seated last month who booked through the app itself (its own app or site). OpenTable: the Network line of its covers report; needed for OpenTable. Other apps: every guest booked through it, wherever they booked."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "partnerCovers": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 1000000000,
                        "description": "OpenTable only: guests who booked through Google and other partners, the report's Partner or Affiliate line. Left out: not counted."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "websiteCovers": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 1000000000,
                        "description": "OpenTable only: guests who booked through the restaurant's own website (a fee each on Basic)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "websiteFlatAddOn": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "OpenTable Basic only: true if the invoice shows the monthly flat fee for website bookings."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "monthlyFee": {
                    "anyOf": [
                      {
                        "description": "The invoice's monthly fee: plan plus add-ons, before fees per guest. Left out: the published price. Needed for sevenrooms and other.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "networkCoverFee": {
                    "anyOf": [
                      {
                        "description": "OpenTable or other only: the fee per guest on the invoice, only if it isn't the published one.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "partnerCoverFee": {
                    "anyOf": [
                      {
                        "description": "OpenTable only: the fee per partner guest, from its Billing History tab. Left out: a range.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "prepaidAmount": {
                    "anyOf": [
                      {
                        "description": "Money the app collected last month, from its statement: deposits, prepayments, no-show charges. tock_: prepayments only.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "prepaidFeePercent": {
                    "anyOf": [
                      {
                        "description": "The app's percentage of that money, as a percent (2 for 2%, not 0.02), only if it isn't the published one.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "averageSpend": {
                    "anyOf": [
                      {
                        "description": "The average spend per guest: net sales ÷ guests, from the POS.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "firstMonth": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "OpenTable Basic only: true if last month was the first 30 days (network guests free)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "renewalDate": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                        "description": "Not on opentable_basic or spoton_reserve: the contract's renewal date, YYYY-MM-DD, from the contract; month-to-month plans have none."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "platform"
                ],
                "additionalProperties": false
              },
              "example": {
                "platform": "opentable_core",
                "networkCovers": 1200,
                "partnerCovers": 300,
                "websiteCovers": 400,
                "prepaidAmount": 2000,
                "averageSpend": 45
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_cash_out": {
      "get": {
        "operationId": "describe_restaurantdoctor_cash_out",
        "summary": "Describe: Nightly cash-out",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_cash_out",
        "summary": "Nightly cash-out",
        "description": "Works out a restaurant's nightly cash close for one drawer and one day or shift, as the free cash-out sheet on restaurantdoctorai.com does: expected cash (starting bank + cash sales - cash tips paid out - paid outs), over or short against the cash counted, the deposit (counted minus the starting bank), the card difference (processor batch minus POS card sales) when both are sent, and comps, voids and discounts as a share of net sales. Takes the starting bank, cash sales and cash counted, plus optional paid outs, card figures and sales totals, in any currency; a figure that isn't sent is never counted as 0. It sets no normal for over or short. Returns the result, how it was worked out, and a link to the free cash-out sheet. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "startingBank": {
                    "anyOf": [
                      {
                        "description": "The cash in the drawer at open: one drawer, one day or shift, in the owner's own currency like every figure here. Needed; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cashSales": {
                    "anyOf": [
                      {
                        "description": "That day's cash payments, from the POS end-of-day (Z) report. Needed; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cashTipsPaidOut": {
                    "anyOf": [
                      {
                        "description": "Optional: card tips paid to staff in cash from this drawer. Taken off expected cash.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "paidOuts": {
                    "anyOf": [
                      {
                        "description": "Optional: cash taken out of the drawer for supplies and the like. Taken off expected cash.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cashCounted": {
                    "anyOf": [
                      {
                        "description": "The cash counted at close, bank included. Needed; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cardSales": {
                    "anyOf": [
                      {
                        "description": "Optional: that day's card sales from the POS. With cardBatch, gives the card difference.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "cardBatch": {
                    "anyOf": [
                      {
                        "description": "Optional: what the card processor settled for the same day. With cardSales.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "netSales": {
                    "anyOf": [
                      {
                        "description": "Optional: that day's net sales from the POS, before tax and tips. Turns comps, voids and discounts into shares.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "comps": {
                    "anyOf": [
                      {
                        "description": "Optional: the day's comps total from the POS. Needs netSales for its share.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "voids": {
                    "anyOf": [
                      {
                        "description": "Optional: the day's voids total from the POS. Needs netSales for its share.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "discounts": {
                    "anyOf": [
                      {
                        "description": "Optional: the day's discounts total from the POS. Needs netSales for its share.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "startingBank": 200,
                "cashSales": 1846.5,
                "cashTipsPaidOut": 120,
                "paidOuts": 35,
                "cashCounted": 1885.5,
                "cardSales": 4212.4,
                "cardBatch": 4199.9,
                "netSales": 6058.9,
                "comps": 90,
                "voids": 36,
                "discounts": 150
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_tip_out": {
      "get": {
        "operationId": "describe_restaurantdoctor_tip_out",
        "summary": "Describe: Tip-out sheet",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_tip_out",
        "summary": "Tip-out sheet",
        "description": "Works out how a restaurant shares tips, two ways, as the free tip-out sheet on restaurantdoctorai.com does. method percent: a server's tip-out to support roles, each a percentage of the server's net sales or tips, with the total tip-out, what the server keeps from their tips, and an error-level check when the tip-out is more than the tips. method pool: a tip pool shared by hours, with optional points for each role, rounded to the cent with the rounding remainder placed on the largest share. Takes the figures in any currency; a figure that isn't sent is never counted as 0. Returns the split, how it was worked out, the Department of Labor's published points on tips with their sources, and a link to the free tip-out sheet. It only works out a split from the numbers sent; it doesn't say whether a tip-out or a tip pool is allowed. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "method": {
                    "type": "string",
                    "enum": [
                      "percent",
                      "pool"
                    ],
                    "description": "percent: one server's tip-out to support roles, each a % of the base. pool: a tip pool shared by hours, with optional points."
                  },
                  "baseKind": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "netSales",
                          "tips"
                        ],
                        "description": "With percent, needed: netSales or tips, what the roles' percentages are taken of."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "base": {
                    "anyOf": [
                      {
                        "description": "With percent, needed: the server's net sales for the shift (before tax and tips), or their tips, as baseKind says. In the owner's own currency.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "tips": {
                    "anyOf": [
                      {
                        "description": "With percent: the server's tips for the shift, to work out what they keep. Not used when baseKind is tips.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "roles": {
                    "anyOf": [
                      {
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "maxLength": 60,
                                  "description": "Optional: the role, such as Bartender or Busser."
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "percent": {
                              "anyOf": [
                                {
                                  "description": "The role's % of the base, 0 to 100. Needed for each role.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 100
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          },
                          "additionalProperties": false
                        },
                        "description": "With percent, needed: the support roles tipped out."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "pool": {
                    "anyOf": [
                      {
                        "description": "With pool, needed: the tips in the pool for the period.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "members": {
                    "anyOf": [
                      {
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "maxLength": 60,
                                  "description": "Optional: the person or role."
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "hours": {
                              "anyOf": [
                                {
                                  "description": "Hours worked in the pool's period. Needed for each person.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "points": {
                              "anyOf": [
                                {
                                  "description": "Optional: the role's weight, such as 1.5, to one decimal. Left out, 1.",
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          },
                          "additionalProperties": false
                        },
                        "description": "With pool, needed: the people or roles sharing the pool."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "method"
                ],
                "additionalProperties": false
              },
              "example": {
                "method": "percent",
                "baseKind": "netSales",
                "base": 1250,
                "tips": 210,
                "roles": [
                  {
                    "name": "Bartender",
                    "percent": 2
                  },
                  {
                    "name": "Busser",
                    "percent": 1.5
                  },
                  {
                    "name": "Food runner",
                    "percent": 1
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_par_levels": {
      "get": {
        "operationId": "describe_restaurantdoctor_par_levels",
        "summary": "Describe: Prep list and par sheet",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_par_levels",
        "summary": "Prep list and par sheet",
        "description": "Works out par levels and what to order for up to 50 kitchen or bar items, as the free prep and par sheet on restaurantdoctorai.com does. Par = use per day × days covered + safety stock (days covered: from the day of the count and the order until the next delivery after this one arrives); order = par minus what's on hand, never below 0, rounded up to whole packs when a pack size is sent. Takes each item's use per day (or per week and the days open a week), days covered, optional safety stock and pack size, and what's on hand, in the owner's own units; a figure that isn't sent is never counted as 0, and an item missing one is returned as incomplete. Returns each item's par and order, the items that need an order, and a link to the free prep and par sheet. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "items": {
                    "anyOf": [
                      {
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "maxLength": 60,
                                  "description": "Optional: the item."
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "unit": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "maxLength": 60,
                                  "description": "Optional: the unit, such as lb or each."
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "usePerDay": {
                              "anyOf": [
                                {
                                  "description": "Units used in a day open. Needed, or usePerWeek.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "usePerWeek": {
                              "anyOf": [
                                {
                                  "description": "Units used in a week: divided by daysOpenPerWeek. Not used when usePerDay is sent.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "daysCovered": {
                              "anyOf": [
                                {
                                  "description": "This item's days covered. Left out, the list's daysCovered.",
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 60
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "safety": {
                              "anyOf": [
                                {
                                  "description": "Optional: units kept on top for a busy day or a late truck. Left out, 0.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "onHand": {
                              "anyOf": [
                                {
                                  "description": "Units on hand when the order is placed. Needed.",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "packSize": {
                              "anyOf": [
                                {
                                  "description": "Optional: units in one pack, to 3 decimals. With it, the order is whole packs.",
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 1000000000
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          },
                          "additionalProperties": false
                        },
                        "description": "Needed: the items, up to 50."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "daysOpenPerWeek": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 7,
                        "description": "Days open a week, 1 to 7. Needed only for items sent with usePerWeek."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "daysCovered": {
                    "anyOf": [
                      {
                        "description": "Days each order covers, for items without their own: from the day of the count and the order to the day the next delivery after this one arrives.",
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 60
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "daysOpenPerWeek": 6,
                "daysCovered": 3,
                "items": [
                  {
                    "name": "Chicken thighs",
                    "unit": "lb",
                    "usePerWeek": 84,
                    "safety": 5,
                    "onHand": 22,
                    "packSize": 10
                  },
                  {
                    "name": "Burger buns",
                    "unit": "each",
                    "usePerDay": 60,
                    "daysCovered": 4,
                    "safety": 24,
                    "onHand": 190,
                    "packSize": 12
                  },
                  {
                    "name": "Yellow onions",
                    "unit": "lb",
                    "usePerDay": 12.5,
                    "onHand": 45
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    },
    "/api/tools/restaurantdoctor_prime_cost_consult": {
      "get": {
        "operationId": "describe_restaurantdoctor_prime_cost_consult",
        "summary": "Describe: Prime cost consult",
        "description": "This tool's description, endpoint, example body and input schema.",
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolDescription"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "restaurantdoctor_prime_cost_consult",
        "summary": "Prime cost consult",
        "description": "Runs the guided consult \"Fix my prime cost\" one step at a time from the answers so far, as RestaurantDoctorAI's AI restaurant expert does on restaurantdoctorai.com: the 6 set questions (type of restaurant, a week or a month, net sales, food and drink invoices, wages, payroll taxes and benefits), a check on any figure that looks like a slip, the free prime cost calculator's result, then up to 5 more questions on the half that comes first, ending in one finding: the biggest problem at these figures, the step-by-step fix to start with, its sources and at most two other things worth a look. Fixed rules and the calculators produce every figure and sentence, with no AI in between. Nothing is kept between calls: the answers so far come in on every call, each one optional, and the reply is the first step still open, with the fields and set answers that answer it. Any number of answers can come in one call. A figure that isn't sent is never counted as 0. A dish is only its price, plate cost and number sold, with no name. A guide, not a promise of results, and not legal, tax or financial advice. The figures aren't stored; only an anonymous daily count of calculator runs is kept.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "format": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "quick_service",
                          "fast_casual",
                          "full_service",
                          "fine_dining",
                          "bar_lounge",
                          "cafe"
                        ],
                        "description": "The type of restaurant, which sets the targets: prime cost, and the ranges for food and drink and for labor: quick_service = Quick service (Counter or kiosk, fast turnover); fast_casual = Fast casual (Order at the counter, served at the table); full_service = Full service / casual dining (Servers, moderate check); fine_dining = Fine dining (Chef-driven, higher check); bar_lounge = Bar, taproom or lounge (Drinks are about half of sales or more); cafe = Café or coffee shop (Drinks lead, with pastries and light food)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "period": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "week",
                          "month"
                        ],
                        "description": "Whether every figure covers one week or one month, the same dates for all of them. Sets how a year is worked out (52 weeks or 12 months)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "payrollIn": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "True when the wages figure already has payroll taxes and benefits in it. A payrollCosts figure then isn't counted."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "estimated": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "sales",
                            "purchases",
                            "wages",
                            "payrollCosts"
                          ]
                        },
                        "description": "Which figures are the owner's own rough estimate: each reads \"(your estimate)\" where the figures are shown."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "skipped": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "format",
                            "period",
                            "sales",
                            "purchases",
                            "wages",
                            "payrollCosts",
                            "stock",
                            "costsKnown",
                            "dishes",
                            "hourlyWages",
                            "hours",
                            "overtimeHours",
                            "owner"
                          ]
                        },
                        "description": "The steps the owner passed on: payrollCosts, stock, hourlyWages, hours, overtimeHours and owner. The others stay open."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "confirmed": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "food:overSales",
                            "food:small",
                            "food:under",
                            "labor:overSales",
                            "labor:primeOverSales",
                            "labor:payrollHigh",
                            "labor:small",
                            "labor:under",
                            "food:dishesOverSales",
                            "food:dishesCheap"
                          ]
                        },
                        "description": "The checks the owner says are right, by the id each check step gives."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "firstHalf": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "food",
                          "labor"
                        ],
                        "description": "Which half comes first when food and drink and labor tie: the answer to the tie step."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "resultSeen": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "True once the result step has been seen. The questions on why come after it, and the finding doesn't repeat the result's lines."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "costsKnown": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "Whether the owner knows what their best sellers cost to plate."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "dishes": {
                    "anyOf": [
                      {
                        "maxItems": 3,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "price": {
                              "description": "Its menu price, in the same currency as the other figures.",
                              "type": "number",
                              "minimum": 0,
                              "maximum": 1000000000
                            },
                            "plateCost": {
                              "description": "What one costs to plate, in the same currency.",
                              "type": "number",
                              "minimum": 0,
                              "maximum": 1000000000
                            },
                            "sold": {
                              "description": "How many sold, for the same dates as the other figures.",
                              "type": "number",
                              "minimum": 0,
                              "maximum": 1000000000
                            }
                          },
                          "required": [
                            "price",
                            "plateCost",
                            "sold"
                          ],
                          "additionalProperties": false
                        },
                        "description": "Up to 3 best sellers, drinks included, for the same dates as the other figures. All 3 can come in one call, and a call's list is the whole list."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "dishesDone": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "True when the list of dishes is finished at fewer than 3, or empty."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hourlyWages": {
                    "anyOf": [
                      {
                        "description": "How much of the wages figure was hourly pay. The rest counts as salaries.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hours": {
                    "anyOf": [
                      {
                        "description": "The hours hourly staff worked, overtime included, from the time clock.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "overtimeHours": {
                    "anyOf": [
                      {
                        "description": "How many of those hours were overtime.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "unpaid": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "False when the owner doesn't work in the restaurant without a salary."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "alsoOther": {
                    "anyOf": [
                      {
                        "type": "boolean",
                        "description": "True for the other half's questions as well, when it's over its range too. They come after the finding and aren't part of it."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "sales": {
                    "anyOf": [
                      {
                        "description": "Net sales for the period, in the owner's own currency like every figure here, from the POS sales summary: after discounts and comps, before tax and tips, with any service charge paid out to staff added back. Needed for a result, and more than 0; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "purchases": {
                    "anyOf": [
                      {
                        "description": "Food and drink supplier invoices for the same dates, added up by delivery date, minus credits. No packaging. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "wages": {
                    "anyOf": [
                      {
                        "description": "Every wage and salary for the same dates, from payroll, managers included (a salary counts as a 52nd of a year for a week, a 12th for a month). No tips, but a service charge paid to staff stays in. Needed for a result; if missing, the reply asks for it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "payrollCosts": {
                    "anyOf": [
                      {
                        "description": "Optional: the employer's payroll taxes and benefits for the period, such as health insurance or a pension, when the wages figure leaves them out.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "openingStock": {
                    "anyOf": [
                      {
                        "description": "Optional: stock at cost at the start of the period. Used only with closingStock: food and drink then becomes what was used, opening + purchases - closing.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "closingStock": {
                    "anyOf": [
                      {
                        "description": "Optional: stock at cost at the end of the period, counted on the same items the invoices cover. Used only with openingStock.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "ownerPay": {
                    "anyOf": [
                      {
                        "description": "Optional: when the owner works in the restaurant without a salary, what they'd pay someone to do their hours, plus the payroll taxes on it. It's a second figure; the main one stays as the books have it.",
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1000000000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "format": "full_service",
                "period": "month",
                "sales": 80000,
                "purchases": 29600,
                "wages": 26000,
                "payrollCosts": 2800
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result, as data and in words.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/TooSlow"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyCalls"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ToolDescription": {
        "type": "object",
        "required": [
          "name",
          "title",
          "description",
          "endpoint",
          "method",
          "example",
          "inputSchema"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "endpoint": {
            "type": "string",
            "format": "uri"
          },
          "method": {
            "type": "string",
            "const": "POST"
          },
          "example": {
            "description": "A body that runs."
          },
          "inputSchema": {
            "type": "object",
            "description": "The tool's input, as JSON Schema."
          }
        }
      },
      "ToolList": {
        "type": "object",
        "required": [
          "about",
          "docs",
          "rateLimit",
          "tools"
        ],
        "properties": {
          "about": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "rateLimit": {
            "type": "string"
          },
          "tools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ToolDescription"
            }
          }
        }
      },
      "ToolResult": {
        "type": "object",
        "required": [
          "tool",
          "result",
          "text"
        ],
        "properties": {
          "tool": {
            "type": "string"
          },
          "result": {
            "description": "The tool's result as data. Its shape is the tool's own."
          },
          "text": {
            "type": "string",
            "description": "The same result in words, as the MCP tool returns it."
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "example": {
            "description": "A body that runs, when the body sent didn't match the input schema."
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The body isn't JSON, doesn't match the input schema, or the tool can't work from it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooLarge": {
        "description": "The body is over 65536 bytes.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooSlow": {
        "description": "The body took too long to arrive.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooManyCalls": {
        "description": "Over the limit of 60 calls a minute from one address. Wait for the seconds in Retry-After.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    }
  }
}
