{
  "openapi": "3.1.1",
  "info": {
    "title": "Weather-Aware Packing List API",
    "version": "1.0.0",
    "summary": "A packing list sized to your trip length, laundry, travellers and the weather at the destination.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://hearthpackinglist.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "A packing list sized to your trip length, laundry, travellers and the weather at the destination.",
        "description": "Builds a packing list with quantities from clear rules: one set of underwear and socks per day until the next wash, layers and rain gear from the expected temperatures and rainy days, plus the extras for beach, hiking, business, winter sports, camping, babies, children and hand-luggage flights. The weather comes from the MET Norway forecast when the trip is near, from 1991–2020 climate normals for Germany and the United States, or from your own numbers.\n\nMethodology:\n- Weather: “automatic” uses the MET Norway Locationforecast 2.0 when the trip starts within eight days (local days of the trip that the forecast covers; a day is rainy with at least 1 mm or three wet hours), otherwise the 1991–2020 climate normals of the nearest station for the months of the trip — Deutscher Wetterdienst (bundled) for Germany, NOAA NCEI for the United States. DWD stations have only a monthly mean temperature; the daily range is then taken as the mean ± 4 °C. Elsewhere, enter your own lowest and highest temperature.\n- Clothes per person: underwear and socks for every day until the next wash plus one spare; one top per day; trousers or shorts for about three days each; a second set of sleepwear for more than a week between washes. Without laundry, trips longer than 14 days assume one wash per fortnight.\n- Weather rules (°C): jumper or fleece below 15; warm coat below 5; hat, gloves and scarf below 3; thermal base layer below −5 or for winter sports; shorts from 22; sandals from 24; swimwear from 26 or for the beach; sun hat from 20 (or for the beach), sunglasses and sunscreen also for winter sports; rain jacket when at least a quarter of the days are rainy, or the month has at least 60 mm of precipitation and no wet-day count (for winter sports the ski jacket covers it).\n- Babies: about six nappies a day (newborns need more), a pack of wipes every three days and two outfits a day until the next wash. Hand luggage only adds a clear 1-litre bag for liquids in containers of up to 100 ml, the rule at most airports. By car: warning triangle, high-visibility vests and a first-aid kit, which many European countries require.\n- Every quantity is a rule of thumb you can change; the list is sorted by category.\n\nA starting point: check entry rules, airline baggage limits and the latest forecast before you travel.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "hearth_packing_list",
        "x-owner-app": "hearth",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HearthPackingListInput"
              },
              "examples": {
                "example1": {
                  "summary": "Munich in April, 6 nights, two adults: climate normals (DWD)",
                  "value": {
                    "place": "48.14, 11.58",
                    "timeZone": "Europe/Berlin",
                    "startDate": "2027-04-12",
                    "nights": 6,
                    "source": "climate",
                    "adults": 2,
                    "styles": [
                      "city"
                    ],
                    "transport": "train"
                  }
                },
                "example2": {
                  "summary": "Beach week with a toddler, hand luggage only, 18–28 °C",
                  "value": {
                    "startDate": "2027-07-03",
                    "nights": 7,
                    "source": "manual",
                    "tMin": 18,
                    "tMax": 28,
                    "rainyDays": 1,
                    "adults": 2,
                    "children": 1,
                    "infants": 1,
                    "laundryEvery": 0,
                    "styles": [
                      "beach"
                    ],
                    "transport": "plane-carry-on"
                  }
                },
                "example3": {
                  "summary": "Two weeks of hiking by car, washing every 5 days, 4–16 °C and rain",
                  "value": {
                    "startDate": "2027-09-06",
                    "nights": 14,
                    "source": "manual",
                    "tMin": 4,
                    "tMax": 16,
                    "rainyDays": 5,
                    "adults": 2,
                    "laundryEvery": 5,
                    "styles": [
                      "hiking",
                      "camping"
                    ],
                    "transport": "car",
                    "extras": [
                      "Binoculars"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HearthPackingListResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "HearthPackingListInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "place": {
            "title": "Destination (latitude, longitude; optional)",
            "description": "Needed for the forecast and climate normals. Rounded to 0.01° (about 1 km) before a request.",
            "type": "string",
            "maxLength": 80,
            "default": ""
          },
          "timeZone": {
            "title": "Time zone of the destination",
            "description": "IANA name such as Europe/Rome. Used to group forecast hours into local days.",
            "type": "string",
            "maxLength": 40,
            "default": "Europe/Berlin"
          },
          "startDate": {
            "title": "First day of the trip",
            "type": "string",
            "format": "date",
            "default": "2027-04-12"
          },
          "nights": {
            "title": "Nights",
            "type": "integer",
            "minimum": 1,
            "maximum": 60,
            "default": 6
          },
          "source": {
            "title": "Weather",
            "type": "string",
            "enum": [
              "auto",
              "forecast",
              "climate",
              "manual"
            ],
            "default": "auto"
          },
          "tMin": {
            "title": "Lowest temperature you expect (°C, for “my own temperatures”)",
            "type": "number",
            "minimum": -50,
            "maximum": 50,
            "x-unit": "°C"
          },
          "tMax": {
            "title": "Highest temperature you expect (°C)",
            "type": "number",
            "minimum": -50,
            "maximum": 55,
            "x-unit": "°C"
          },
          "rainyDays": {
            "title": "Rainy days you expect (optional)",
            "type": "integer",
            "minimum": 0,
            "maximum": 61
          },
          "adults": {
            "title": "Adults and teenagers",
            "type": "integer",
            "minimum": 0,
            "maximum": 12,
            "default": 2
          },
          "children": {
            "title": "Children",
            "type": "integer",
            "minimum": 0,
            "maximum": 12,
            "default": 0
          },
          "infants": {
            "title": "Babies and toddlers in nappies",
            "type": "integer",
            "minimum": 0,
            "maximum": 12,
            "default": 0
          },
          "laundryEvery": {
            "title": "Wash clothes every … days (0 = no laundry)",
            "type": "integer",
            "minimum": 0,
            "maximum": 30,
            "default": 0
          },
          "styles": {
            "title": "Kind of trip",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "city",
                "beach",
                "hiking",
                "business",
                "winter-sports",
                "camping"
              ]
            },
            "default": [
              "city"
            ]
          },
          "transport": {
            "title": "Travelling by",
            "type": "string",
            "enum": [
              "plane-carry-on",
              "plane-checked",
              "car",
              "train"
            ],
            "default": "plane-checked"
          },
          "extras": {
            "title": "Your own items (optional)",
            "description": "One item per line, for example “Camera”.",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 30
          }
        },
        "required": [
          "startDate"
        ]
      },
      "HearthPackingListResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "days",
              "nights",
              "travellers",
              "washCycleDays",
              "weather",
              "rainGear",
              "styles",
              "transport",
              "items",
              "totalPieces",
              "warnings"
            ],
            "properties": {
              "days": {
                "type": "integer"
              },
              "nights": {
                "type": "integer"
              },
              "travellers": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "adults",
                  "children",
                  "infants"
                ],
                "properties": {
                  "adults": {
                    "type": "integer"
                  },
                  "children": {
                    "type": "integer"
                  },
                  "infants": {
                    "type": "integer"
                  }
                }
              },
              "washCycleDays": {
                "type": "integer"
              },
              "weather": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "source",
                  "tMin",
                  "tMax",
                  "rainyDays",
                  "rainShare",
                  "wetMonth",
                  "days",
                  "coveredDays",
                  "station",
                  "stationSource",
                  "note"
                ],
                "properties": {
                  "source": {
                    "enum": [
                      "forecast",
                      "climate",
                      "manual"
                    ]
                  },
                  "stationSource": {
                    "enum": [
                      "",
                      "dwd",
                      "noaa"
                    ]
                  },
                  "tMin": {
                    "type": "number"
                  },
                  "tMax": {
                    "type": "number"
                  },
                  "rainyDays": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "rainShare": {
                    "type": "number"
                  },
                  "wetMonth": {
                    "type": "boolean"
                  },
                  "days": {
                    "type": "integer"
                  },
                  "coveredDays": {
                    "type": "integer"
                  },
                  "station": {
                    "type": "string"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              },
              "rainGear": {
                "type": "boolean"
              },
              "styles": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "transport": {
                "type": "string"
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "label",
                    "category",
                    "qty",
                    "perPerson",
                    "reason"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "qty": {
                      "type": "integer"
                    },
                    "perPerson": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              },
              "totalPieces": {
                "type": "integer"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}