{
  "openapi": "3.1.0",
  "info": {
    "title": "Splot API",
    "version": "1.0.0",
    "description": "Read and write your Splot food journal with a personal API key. Meals and foods saved through the API follow the same rules as the app and connected assistants."
  },
  "servers": [
    {
      "url": "https://app.splot.health/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Meals",
      "description": "Log, plan, read, change and delete meals."
    },
    {
      "name": "Foods",
      "description": "Search foods, save or delete your own, and follow the changes you proposed to products."
    },
    {
      "name": "Settings",
      "description": "Read and change your daily targets, display preferences and body measurements."
    }
  ],
  "paths": {
    "/meals": {
      "get": {
        "operationId": "listMeals",
        "summary": "List meals",
        "description": "Lists your meals, newest first, a page at a time.",
        "tags": [
          "Meals"
        ],
        "x-permission": "read",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Only meals in this state.",
            "schema": {
              "type": "string",
              "enum": [
                "planned",
                "logged"
              ]
            }
          },
          {
            "name": "day",
            "in": "query",
            "required": false,
            "description": "Only meals on this day, in the timezone each was eaten in.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "fromDay",
            "in": "query",
            "required": false,
            "description": "Only meals on this day or later.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "toDay",
            "in": "query",
            "required": false,
            "description": "Only meals on this day or earlier.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Only meals eaten at or after this time, with a UTC offset.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Only meals eaten before this time, with a UTC offset.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return.",
            "schema": {
              "default": 20,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip. Send the previous page's `nextOffset`.",
            "schema": {
              "default": 0,
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of meals.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createMeal",
        "summary": "Create a meal",
        "description": "Logs a meal you ate, or plans one ahead.",
        "tags": [
          "Meals"
        ],
        "x-permission": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new meal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meal"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "A food the meal points at doesn't exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A new food has a barcode the catalogue already knows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/meals/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "The meal's id.",
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "operationId": "getMeal",
        "summary": "Retrieve a meal",
        "description": "Reads one meal and its items.",
        "tags": [
          "Meals"
        ],
        "x-permission": "read",
        "responses": {
          "200": {
            "description": "The meal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meal"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The meal doesn't exist, or isn't yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateMeal",
        "summary": "Update a meal",
        "description": "Changes a meal. Only what you send changes.",
        "tags": [
          "Meals"
        ],
        "x-permission": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated meal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meal"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The meal doesn't exist, or isn't yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteMeal",
        "summary": "Delete a meal",
        "description": "Deletes a meal, its history and its photos.",
        "tags": [
          "Meals"
        ],
        "x-permission": "write",
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The meal doesn't exist, or isn't yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/foods": {
      "get": {
        "operationId": "searchFoods",
        "summary": "Search foods",
        "description": "Finds foods to log in one library, by name, brand or barcode.",
        "tags": [
          "Foods"
        ],
        "x-permission": "read",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": false,
            "description": "Words from the name or brand, or a whole barcode. Generic ingredients need three characters or more.",
            "schema": {
              "default": "",
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "library",
            "in": "query",
            "required": false,
            "description": "The library to search.",
            "schema": {
              "default": "mine",
              "type": "string",
              "enum": [
                "off",
                "splot",
                "mine",
                "composition"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return.",
            "schema": {
              "default": 30,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip. Send the previous page's `nextOffset`.",
            "schema": {
              "default": 0,
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "locale",
            "in": "query",
            "required": false,
            "description": "A language, such as `de`. Generic ingredients are named in it where they can be.",
            "schema": {
              "type": "string",
              "maxLength": 80,
              "pattern": "^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$"
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "A two-letter country, such as `DE`. Open Food Facts lists its products first.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of foods.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoodPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "saveFood",
        "summary": "Save a food",
        "description": "Saves a food or recipe to your foods, or changes one you saved.",
        "tags": [
          "Foods"
        ],
        "x-permission": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FoodInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The saved food.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Food"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The food to change, or an ingredient, doesn't exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The barcode is already in the catalogue. The body's `food` is the one to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/food-corrections": {
      "get": {
        "operationId": "listFoodCorrections",
        "summary": "List food corrections",
        "description": "Lists the changes you made to catalogue products, newest first, and where their review stands.",
        "tags": [
          "Foods"
        ],
        "x-permission": "read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return.",
            "schema": {
              "default": 30,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip. Send the previous page's `nextOffset`.",
            "schema": {
              "default": 0,
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of corrections.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CorrectionPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/settings": {
      "get": {
        "operationId": "getSettings",
        "summary": "Retrieve settings",
        "description": "Reads your daily targets, display preferences and body measurements.",
        "tags": [
          "Settings"
        ],
        "x-permission": "read",
        "responses": {
          "200": {
            "description": "Your settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settings"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateSettings",
        "summary": "Update settings",
        "description": "Changes your daily targets, display preferences or body measurements. Only what you send changes.",
        "tags": [
          "Settings"
        ],
        "x-permission": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettingsChange"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your settings after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settings"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/foods/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "The food's id.",
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "delete": {
        "operationId": "deleteFood",
        "summary": "Delete a food",
        "description": "Removes a food from your foods. Past meals and recipes keep it.",
        "tags": [
          "Foods"
        ],
        "x-permission": "write",
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "400": {
            "$ref": "#/components/responses/InvalidInput"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The food doesn't exist, or isn't yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A personal API key from Account → API Keys in the Splot app."
      }
    },
    "schemas": {
      "NewFood": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The food's name."
          },
          "brand": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand, for a packaged product."
          },
          "barcode": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{8,14}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "The barcode: 8 to 14 digits."
          },
          "data": {
            "type": "object",
            "properties": {
              "base": {
                "type": "string",
                "enum": [
                  "g",
                  "ml",
                  "serving"
                ],
                "description": "The unit nutrition is given in."
              },
              "nutrition": {
                "type": "object",
                "properties": {
                  "basisAmount": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999,
                    "description": "How much of the base unit the values are for."
                  },
                  "values": {
                    "type": "object",
                    "properties": {
                      "kcal": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "protein": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "carbs": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "fat": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "saturatedFat": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "sugars": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "fibre": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "salt": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      }
                    },
                    "additionalProperties": false,
                    "description": "kcal, and grams of protein, carbs, fat, saturated fat, sugars, fibre and salt."
                  }
                },
                "required": [
                  "basisAmount",
                  "values"
                ],
                "additionalProperties": false,
                "description": "Nutrients for `basisAmount` of the base unit, such as per 100 g. A nutrient left out is unknown, not zero."
              },
              "measures": {
                "maxItems": 30,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 100
                    },
                    "size": {
                      "type": "number",
                      "exclusiveMinimum": 0,
                      "maximum": 999999999.999
                    }
                  },
                  "required": [
                    "label",
                    "size"
                  ],
                  "additionalProperties": false
                },
                "description": "Other portions by name, each `{ \"label\", \"size\" }` in the base unit, such as a tablespoon of 15 g."
              },
              "defaultPortion": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "unit": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  }
                },
                "required": [
                  "amount",
                  "unit"
                ],
                "additionalProperties": false,
                "description": "The usual portion, as `{ \"amount\", \"unit\" }`."
              },
              "composition": {
                "type": "string",
                "maxLength": 10000,
                "description": "Ingredients as printed on the label."
              },
              "note": {
                "type": "string",
                "maxLength": 10000,
                "description": "Anything else worth knowing."
              },
              "images": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string",
                          "maxLength": 2000,
                          "format": "uri"
                        }
                      },
                      "required": [
                        "url"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 500
                        }
                      },
                      "required": [
                        "path"
                      ],
                      "additionalProperties": false
                    }
                  ]
                },
                "description": "Photos, as public links or saved Splot photos."
              },
              "recipe": {
                "type": "object",
                "properties": {
                  "servings": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "minutes": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "steps": {
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 2000
                    }
                  }
                },
                "required": [
                  "servings",
                  "steps"
                ],
                "additionalProperties": false,
                "description": "For a recipe: its `servings`, optional `minutes`, and `steps`."
              },
              "source": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "enum": [
                      "label",
                      "restaurant",
                      "manual",
                      "estimate",
                      "ingredients"
                    ]
                  },
                  "by": {
                    "type": "string",
                    "const": "chatgpt"
                  },
                  "place": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "edited": {
                    "type": "boolean"
                  },
                  "library": {
                    "type": "string",
                    "enum": [
                      "splot",
                      "off",
                      "mine",
                      "composition"
                    ]
                  },
                  "key": {
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "additionalProperties": false,
                "description": "Where the values come from, such as `{ \"origin\": \"label\" }`, or `estimate` with a `description`."
              },
              "ingredients": {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "food": {
                      "type": "object",
                      "properties": {
                        "library": {
                          "type": "string",
                          "enum": [
                            "off",
                            "splot",
                            "mine",
                            "composition"
                          ]
                        },
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "version": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        }
                      },
                      "required": [
                        "library",
                        "key"
                      ]
                    },
                    "newFood": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "brand": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 200
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "barcode": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^\\d{8,14}$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "data": {
                          "type": "object",
                          "properties": {
                            "base": {
                              "type": "string",
                              "enum": [
                                "g",
                                "ml",
                                "serving"
                              ]
                            },
                            "nutrition": {
                              "type": "object",
                              "properties": {
                                "basisAmount": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "values": {
                                  "type": "object",
                                  "properties": {
                                    "kcal": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "protein": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "carbs": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "fat": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "saturatedFat": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "sugars": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "fibre": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "salt": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    }
                                  },
                                  "additionalProperties": false
                                }
                              },
                              "required": [
                                "basisAmount",
                                "values"
                              ],
                              "additionalProperties": false
                            },
                            "measures": {
                              "maxItems": 30,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 100
                                  },
                                  "size": {
                                    "type": "number",
                                    "exclusiveMinimum": 0,
                                    "maximum": 999999999.999
                                  }
                                },
                                "required": [
                                  "label",
                                  "size"
                                ],
                                "additionalProperties": false
                              }
                            },
                            "defaultPortion": {
                              "type": "object",
                              "properties": {
                                "amount": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "unit": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 100
                                }
                              },
                              "required": [
                                "amount",
                                "unit"
                              ],
                              "additionalProperties": false
                            },
                            "composition": {
                              "type": "string",
                              "maxLength": 10000
                            },
                            "note": {
                              "type": "string",
                              "maxLength": 10000
                            },
                            "images": {
                              "maxItems": 20,
                              "type": "array",
                              "items": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "url": {
                                        "type": "string",
                                        "maxLength": 2000,
                                        "format": "uri"
                                      }
                                    },
                                    "required": [
                                      "url"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "path": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 500
                                      }
                                    },
                                    "required": [
                                      "path"
                                    ],
                                    "additionalProperties": false
                                  }
                                ]
                              }
                            },
                            "recipe": {
                              "type": "object",
                              "properties": {
                                "servings": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "minutes": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "steps": {
                                  "maxItems": 100,
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "maxLength": 2000
                                  }
                                }
                              },
                              "required": [
                                "servings",
                                "steps"
                              ],
                              "additionalProperties": false
                            },
                            "source": {
                              "type": "object",
                              "properties": {
                                "origin": {
                                  "type": "string",
                                  "enum": [
                                    "label",
                                    "restaurant",
                                    "manual",
                                    "estimate",
                                    "ingredients"
                                  ]
                                },
                                "by": {
                                  "type": "string",
                                  "const": "chatgpt"
                                },
                                "place": {
                                  "type": "string",
                                  "maxLength": 200
                                },
                                "description": {
                                  "type": "string",
                                  "maxLength": 2000
                                },
                                "edited": {
                                  "type": "boolean"
                                },
                                "library": {
                                  "type": "string",
                                  "enum": [
                                    "splot",
                                    "off",
                                    "mine",
                                    "composition"
                                  ]
                                },
                                "key": {
                                  "type": "string",
                                  "maxLength": 200
                                }
                              },
                              "additionalProperties": false
                            },
                            "ingredients": {
                              "maxItems": 100,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "food": {
                                    "type": "object",
                                    "properties": {
                                      "library": {
                                        "type": "string",
                                        "enum": [
                                          "off",
                                          "splot",
                                          "mine",
                                          "composition"
                                        ]
                                      },
                                      "key": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 200
                                      },
                                      "version": {
                                        "type": "integer",
                                        "exclusiveMinimum": 0
                                      }
                                    },
                                    "required": [
                                      "library",
                                      "key"
                                    ]
                                  },
                                  "newFood": {
                                    "type": "object",
                                    "properties": {
                                      "name": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 200
                                      },
                                      "brand": {
                                        "anyOf": [
                                          {
                                            "type": "string",
                                            "maxLength": 200
                                          },
                                          {
                                            "type": "null"
                                          }
                                        ]
                                      },
                                      "barcode": {
                                        "anyOf": [
                                          {
                                            "type": "string",
                                            "pattern": "^\\d{8,14}$"
                                          },
                                          {
                                            "type": "null"
                                          }
                                        ]
                                      },
                                      "data": {
                                        "type": "object",
                                        "properties": {
                                          "base": {
                                            "type": "string",
                                            "enum": [
                                              "g",
                                              "ml",
                                              "serving"
                                            ]
                                          },
                                          "nutrition": {
                                            "type": "object",
                                            "properties": {
                                              "basisAmount": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "values": {
                                                "type": "object",
                                                "properties": {
                                                  "kcal": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "protein": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "carbs": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "fat": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "saturatedFat": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "sugars": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "fibre": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "salt": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  }
                                                },
                                                "additionalProperties": false
                                              }
                                            },
                                            "required": [
                                              "basisAmount",
                                              "values"
                                            ],
                                            "additionalProperties": false
                                          },
                                          "measures": {
                                            "maxItems": 30,
                                            "type": "array",
                                            "items": {
                                              "type": "object",
                                              "properties": {
                                                "label": {
                                                  "type": "string",
                                                  "minLength": 1,
                                                  "maxLength": 100
                                                },
                                                "size": {
                                                  "type": "number",
                                                  "exclusiveMinimum": 0,
                                                  "maximum": 999999999.999
                                                }
                                              },
                                              "required": [
                                                "label",
                                                "size"
                                              ],
                                              "additionalProperties": false
                                            }
                                          },
                                          "defaultPortion": {
                                            "type": "object",
                                            "properties": {
                                              "amount": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "unit": {
                                                "type": "string",
                                                "minLength": 1,
                                                "maxLength": 100
                                              }
                                            },
                                            "required": [
                                              "amount",
                                              "unit"
                                            ],
                                            "additionalProperties": false
                                          },
                                          "composition": {
                                            "type": "string",
                                            "maxLength": 10000
                                          },
                                          "note": {
                                            "type": "string",
                                            "maxLength": 10000
                                          },
                                          "images": {
                                            "maxItems": 20,
                                            "type": "array",
                                            "items": {
                                              "anyOf": [
                                                {
                                                  "type": "object",
                                                  "properties": {
                                                    "url": {
                                                      "type": "string",
                                                      "maxLength": 2000,
                                                      "format": "uri"
                                                    }
                                                  },
                                                  "required": [
                                                    "url"
                                                  ],
                                                  "additionalProperties": false
                                                },
                                                {
                                                  "type": "object",
                                                  "properties": {
                                                    "path": {
                                                      "type": "string",
                                                      "minLength": 1,
                                                      "maxLength": 500
                                                    }
                                                  },
                                                  "required": [
                                                    "path"
                                                  ],
                                                  "additionalProperties": false
                                                }
                                              ]
                                            }
                                          },
                                          "recipe": {
                                            "type": "object",
                                            "properties": {
                                              "servings": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "minutes": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "steps": {
                                                "maxItems": 100,
                                                "type": "array",
                                                "items": {
                                                  "type": "string",
                                                  "maxLength": 2000
                                                }
                                              }
                                            },
                                            "required": [
                                              "servings",
                                              "steps"
                                            ],
                                            "additionalProperties": false
                                          },
                                          "source": {
                                            "type": "object",
                                            "properties": {
                                              "origin": {
                                                "type": "string",
                                                "enum": [
                                                  "label",
                                                  "restaurant",
                                                  "manual",
                                                  "estimate",
                                                  "ingredients"
                                                ]
                                              },
                                              "by": {
                                                "type": "string",
                                                "const": "chatgpt"
                                              },
                                              "place": {
                                                "type": "string",
                                                "maxLength": 200
                                              },
                                              "description": {
                                                "type": "string",
                                                "maxLength": 2000
                                              },
                                              "edited": {
                                                "type": "boolean"
                                              },
                                              "library": {
                                                "type": "string",
                                                "enum": [
                                                  "splot",
                                                  "off",
                                                  "mine",
                                                  "composition"
                                                ]
                                              },
                                              "key": {
                                                "type": "string",
                                                "maxLength": 200
                                              }
                                            },
                                            "additionalProperties": false
                                          }
                                        },
                                        "additionalProperties": false
                                      },
                                      "copyFrom": {
                                        "type": "object",
                                        "properties": {
                                          "library": {
                                            "type": "string",
                                            "enum": [
                                              "off",
                                              "splot",
                                              "mine",
                                              "composition"
                                            ]
                                          },
                                          "key": {
                                            "type": "string",
                                            "minLength": 1,
                                            "maxLength": 200
                                          }
                                        },
                                        "required": [
                                          "library",
                                          "key"
                                        ],
                                        "additionalProperties": false
                                      }
                                    },
                                    "required": [
                                      "name",
                                      "data"
                                    ],
                                    "additionalProperties": false
                                  },
                                  "portion": {
                                    "type": "object",
                                    "properties": {
                                      "amount": {
                                        "type": "number",
                                        "exclusiveMinimum": 0,
                                        "maximum": 999999999.999
                                      },
                                      "unit": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 100
                                      }
                                    },
                                    "required": [
                                      "amount",
                                      "unit"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "additionalProperties": false
                              }
                            }
                          },
                          "additionalProperties": false
                        },
                        "copyFrom": {
                          "type": "object",
                          "properties": {
                            "library": {
                              "type": "string",
                              "enum": [
                                "off",
                                "splot",
                                "mine",
                                "composition"
                              ]
                            },
                            "key": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 200
                            }
                          },
                          "required": [
                            "library",
                            "key"
                          ],
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "name",
                        "data"
                      ],
                      "additionalProperties": false
                    },
                    "portion": {
                      "type": "object",
                      "properties": {
                        "amount": {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 999999999.999
                        },
                        "unit": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "amount",
                        "unit"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "additionalProperties": false
                },
                "description": "For a recipe: its foods, each with a `portion`."
              }
            },
            "additionalProperties": false,
            "description": "Nutrition, portions and recipe details."
          },
          "copyFrom": {
            "type": "object",
            "properties": {
              "library": {
                "type": "string",
                "enum": [
                  "off",
                  "splot",
                  "mine",
                  "composition"
                ]
              },
              "key": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "library",
              "key"
            ],
            "additionalProperties": false,
            "description": "The food this one was changed from, as `{ \"library\", \"key\" }`, so where it came from is kept."
          }
        },
        "required": [
          "name",
          "data"
        ],
        "additionalProperties": false
      },
      "MealInput": {
        "type": "object",
        "properties": {
          "state": {
            "default": "logged",
            "type": "string",
            "enum": [
              "planned",
              "logged"
            ],
            "description": "Whether the meal was eaten or is planned ahead."
          },
          "images": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "maxLength": 2000,
                      "format": "uri"
                    }
                  },
                  "required": [
                    "url"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 500
                    }
                  },
                  "required": [
                    "path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Photos: public links as `{ \"url\" }`, or saved Splot photos as `{ \"path\" }` from an earlier read."
          },
          "eatenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was eaten, or will be for a plan, with a UTC offset."
          },
          "timezone": {
            "type": "string",
            "maxLength": 100,
            "description": "The IANA timezone it is eaten in, such as `Europe/Berlin`."
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "A name, such as Breakfast."
          },
          "notes": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "Notes about the meal."
          },
          "items": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "food": {
                  "type": "object",
                  "properties": {
                    "library": {
                      "type": "string",
                      "enum": [
                        "off",
                        "splot",
                        "mine",
                        "composition"
                      ],
                      "description": "The library the food is in."
                    },
                    "key": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200,
                      "description": "The food's key in that library."
                    },
                    "version": {
                      "type": "integer",
                      "exclusiveMinimum": 0,
                      "description": "Only to keep the version a saved meal already has. Leave out to use the food as it is now."
                    }
                  },
                  "required": [
                    "library",
                    "key"
                  ],
                  "description": "A food that exists: its `library` and `key` from a food search."
                },
                "newFood": {
                  "$ref": "#/components/schemas/NewFood",
                  "description": "A food that isn't in Splot yet, as saving a food takes it. It is saved to your foods first."
                },
                "quantity": {
                  "anyOf": [
                    {
                      "type": "number",
                      "exclusiveMinimum": 0,
                      "maximum": 999999999.999,
                      "multipleOf": 0.001
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "How much was eaten, in `unit`. Send it with `unit`, or leave both out."
                },
                "unit": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2000
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The food's base unit (`g`, `ml` or `serving`) or one of its measures."
                }
              },
              "additionalProperties": false
            },
            "description": "What was eaten."
          }
        },
        "required": [
          "eatenAt",
          "timezone",
          "items"
        ],
        "additionalProperties": false
      },
      "MealUpdate": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "planned",
              "logged"
            ],
            "description": "Whether the meal was eaten or is planned ahead. Send `logged` when a planned meal is eaten."
          },
          "eatenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was eaten, or will be for a plan, with a UTC offset."
          },
          "timezone": {
            "type": "string",
            "maxLength": 100,
            "description": "The IANA timezone it is eaten in, such as `Europe/Berlin`."
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "The meal's name. `null` clears it."
          },
          "notes": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "The meal's notes. `null` clears them."
          },
          "images": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "maxLength": 2000,
                      "format": "uri"
                    }
                  },
                  "required": [
                    "url"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 500
                    }
                  },
                  "required": [
                    "path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Replaces the meal's photos. Keep a saved photo by sending it as the meal returned it."
          },
          "items": {
            "type": "object",
            "properties": {
              "add": {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "food": {
                      "type": "object",
                      "properties": {
                        "library": {
                          "type": "string",
                          "enum": [
                            "off",
                            "splot",
                            "mine",
                            "composition"
                          ]
                        },
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "version": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        }
                      },
                      "required": [
                        "library",
                        "key"
                      ]
                    },
                    "newFood": {
                      "$ref": "#/components/schemas/NewFood"
                    },
                    "quantity": {
                      "anyOf": [
                        {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 999999999.999,
                          "multipleOf": 0.001
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "unit": {
                      "anyOf": [
                        {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 2000
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "additionalProperties": false
                },
                "description": "New items, as creating a meal takes them."
              },
              "change": {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "The item's id."
                    },
                    "quantity": {
                      "anyOf": [
                        {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 999999999.999,
                          "multipleOf": 0.001
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "The new amount, or `null` with `unit` to clear the portion."
                    },
                    "unit": {
                      "anyOf": [
                        {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 2000
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "The new unit, or `null` with `quantity`."
                    }
                  },
                  "required": [
                    "id",
                    "quantity",
                    "unit"
                  ],
                  "additionalProperties": false
                },
                "description": "New portions for items, by id."
              },
              "remove": {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uuid"
                },
                "description": "Ids of items to remove."
              }
            },
            "additionalProperties": false,
            "description": "Items to add, change or remove."
          }
        },
        "required": [],
        "additionalProperties": false
      },
      "FoodInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The food's name."
          },
          "brand": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "description": "The brand, for a packaged product."
          },
          "barcode": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{8,14}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "The barcode: 8 to 14 digits."
          },
          "data": {
            "type": "object",
            "properties": {
              "base": {
                "type": "string",
                "enum": [
                  "g",
                  "ml",
                  "serving"
                ],
                "description": "The unit nutrition is given in."
              },
              "nutrition": {
                "type": "object",
                "properties": {
                  "basisAmount": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999,
                    "description": "How much of the base unit the values are for."
                  },
                  "values": {
                    "type": "object",
                    "properties": {
                      "kcal": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "protein": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "carbs": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "fat": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "saturatedFat": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "sugars": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "fibre": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "salt": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      }
                    },
                    "additionalProperties": false,
                    "description": "kcal, and grams of protein, carbs, fat, saturated fat, sugars, fibre and salt."
                  }
                },
                "required": [
                  "basisAmount",
                  "values"
                ],
                "additionalProperties": false,
                "description": "Nutrients for `basisAmount` of the base unit, such as per 100 g. A nutrient left out is unknown, not zero."
              },
              "measures": {
                "maxItems": 30,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 100
                    },
                    "size": {
                      "type": "number",
                      "exclusiveMinimum": 0,
                      "maximum": 999999999.999
                    }
                  },
                  "required": [
                    "label",
                    "size"
                  ],
                  "additionalProperties": false
                },
                "description": "Other portions by name, each `{ \"label\", \"size\" }` in the base unit, such as a tablespoon of 15 g."
              },
              "defaultPortion": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "unit": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  }
                },
                "required": [
                  "amount",
                  "unit"
                ],
                "additionalProperties": false,
                "description": "The usual portion, as `{ \"amount\", \"unit\" }`."
              },
              "composition": {
                "type": "string",
                "maxLength": 10000,
                "description": "Ingredients as printed on the label."
              },
              "note": {
                "type": "string",
                "maxLength": 10000,
                "description": "Anything else worth knowing."
              },
              "images": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string",
                          "maxLength": 2000,
                          "format": "uri"
                        }
                      },
                      "required": [
                        "url"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 500
                        }
                      },
                      "required": [
                        "path"
                      ],
                      "additionalProperties": false
                    }
                  ]
                },
                "description": "Photos, as public links or saved Splot photos."
              },
              "recipe": {
                "type": "object",
                "properties": {
                  "servings": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "minutes": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "steps": {
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 2000
                    }
                  }
                },
                "required": [
                  "servings",
                  "steps"
                ],
                "additionalProperties": false,
                "description": "For a recipe: its `servings`, optional `minutes`, and `steps`."
              },
              "source": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "enum": [
                      "label",
                      "restaurant",
                      "manual",
                      "estimate",
                      "ingredients"
                    ]
                  },
                  "by": {
                    "type": "string",
                    "const": "chatgpt"
                  },
                  "place": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "edited": {
                    "type": "boolean"
                  },
                  "library": {
                    "type": "string",
                    "enum": [
                      "splot",
                      "off",
                      "mine",
                      "composition"
                    ]
                  },
                  "key": {
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "additionalProperties": false,
                "description": "Where the values come from, such as `{ \"origin\": \"label\" }`, or `estimate` with a `description`."
              },
              "ingredients": {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "food": {
                      "type": "object",
                      "properties": {
                        "library": {
                          "type": "string",
                          "enum": [
                            "off",
                            "splot",
                            "mine",
                            "composition"
                          ]
                        },
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "version": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        }
                      },
                      "required": [
                        "library",
                        "key"
                      ]
                    },
                    "newFood": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "brand": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 200
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "barcode": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^\\d{8,14}$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "data": {
                          "type": "object",
                          "properties": {
                            "base": {
                              "type": "string",
                              "enum": [
                                "g",
                                "ml",
                                "serving"
                              ]
                            },
                            "nutrition": {
                              "type": "object",
                              "properties": {
                                "basisAmount": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "values": {
                                  "type": "object",
                                  "properties": {
                                    "kcal": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "protein": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "carbs": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "fat": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "saturatedFat": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "sugars": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "fibre": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    },
                                    "salt": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 999999999.999
                                    }
                                  },
                                  "additionalProperties": false
                                }
                              },
                              "required": [
                                "basisAmount",
                                "values"
                              ],
                              "additionalProperties": false
                            },
                            "measures": {
                              "maxItems": 30,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 100
                                  },
                                  "size": {
                                    "type": "number",
                                    "exclusiveMinimum": 0,
                                    "maximum": 999999999.999
                                  }
                                },
                                "required": [
                                  "label",
                                  "size"
                                ],
                                "additionalProperties": false
                              }
                            },
                            "defaultPortion": {
                              "type": "object",
                              "properties": {
                                "amount": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "unit": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 100
                                }
                              },
                              "required": [
                                "amount",
                                "unit"
                              ],
                              "additionalProperties": false
                            },
                            "composition": {
                              "type": "string",
                              "maxLength": 10000
                            },
                            "note": {
                              "type": "string",
                              "maxLength": 10000
                            },
                            "images": {
                              "maxItems": 20,
                              "type": "array",
                              "items": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "url": {
                                        "type": "string",
                                        "maxLength": 2000,
                                        "format": "uri"
                                      }
                                    },
                                    "required": [
                                      "url"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "path": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 500
                                      }
                                    },
                                    "required": [
                                      "path"
                                    ],
                                    "additionalProperties": false
                                  }
                                ]
                              }
                            },
                            "recipe": {
                              "type": "object",
                              "properties": {
                                "servings": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "minutes": {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 999999999.999
                                },
                                "steps": {
                                  "maxItems": 100,
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "maxLength": 2000
                                  }
                                }
                              },
                              "required": [
                                "servings",
                                "steps"
                              ],
                              "additionalProperties": false
                            },
                            "source": {
                              "type": "object",
                              "properties": {
                                "origin": {
                                  "type": "string",
                                  "enum": [
                                    "label",
                                    "restaurant",
                                    "manual",
                                    "estimate",
                                    "ingredients"
                                  ]
                                },
                                "by": {
                                  "type": "string",
                                  "const": "chatgpt"
                                },
                                "place": {
                                  "type": "string",
                                  "maxLength": 200
                                },
                                "description": {
                                  "type": "string",
                                  "maxLength": 2000
                                },
                                "edited": {
                                  "type": "boolean"
                                },
                                "library": {
                                  "type": "string",
                                  "enum": [
                                    "splot",
                                    "off",
                                    "mine",
                                    "composition"
                                  ]
                                },
                                "key": {
                                  "type": "string",
                                  "maxLength": 200
                                }
                              },
                              "additionalProperties": false
                            },
                            "ingredients": {
                              "maxItems": 100,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "food": {
                                    "type": "object",
                                    "properties": {
                                      "library": {
                                        "type": "string",
                                        "enum": [
                                          "off",
                                          "splot",
                                          "mine",
                                          "composition"
                                        ]
                                      },
                                      "key": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 200
                                      },
                                      "version": {
                                        "type": "integer",
                                        "exclusiveMinimum": 0
                                      }
                                    },
                                    "required": [
                                      "library",
                                      "key"
                                    ]
                                  },
                                  "newFood": {
                                    "type": "object",
                                    "properties": {
                                      "name": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 200
                                      },
                                      "brand": {
                                        "anyOf": [
                                          {
                                            "type": "string",
                                            "maxLength": 200
                                          },
                                          {
                                            "type": "null"
                                          }
                                        ]
                                      },
                                      "barcode": {
                                        "anyOf": [
                                          {
                                            "type": "string",
                                            "pattern": "^\\d{8,14}$"
                                          },
                                          {
                                            "type": "null"
                                          }
                                        ]
                                      },
                                      "data": {
                                        "type": "object",
                                        "properties": {
                                          "base": {
                                            "type": "string",
                                            "enum": [
                                              "g",
                                              "ml",
                                              "serving"
                                            ]
                                          },
                                          "nutrition": {
                                            "type": "object",
                                            "properties": {
                                              "basisAmount": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "values": {
                                                "type": "object",
                                                "properties": {
                                                  "kcal": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "protein": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "carbs": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "fat": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "saturatedFat": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "sugars": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "fibre": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  },
                                                  "salt": {
                                                    "type": "number",
                                                    "minimum": 0,
                                                    "maximum": 999999999.999
                                                  }
                                                },
                                                "additionalProperties": false
                                              }
                                            },
                                            "required": [
                                              "basisAmount",
                                              "values"
                                            ],
                                            "additionalProperties": false
                                          },
                                          "measures": {
                                            "maxItems": 30,
                                            "type": "array",
                                            "items": {
                                              "type": "object",
                                              "properties": {
                                                "label": {
                                                  "type": "string",
                                                  "minLength": 1,
                                                  "maxLength": 100
                                                },
                                                "size": {
                                                  "type": "number",
                                                  "exclusiveMinimum": 0,
                                                  "maximum": 999999999.999
                                                }
                                              },
                                              "required": [
                                                "label",
                                                "size"
                                              ],
                                              "additionalProperties": false
                                            }
                                          },
                                          "defaultPortion": {
                                            "type": "object",
                                            "properties": {
                                              "amount": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "unit": {
                                                "type": "string",
                                                "minLength": 1,
                                                "maxLength": 100
                                              }
                                            },
                                            "required": [
                                              "amount",
                                              "unit"
                                            ],
                                            "additionalProperties": false
                                          },
                                          "composition": {
                                            "type": "string",
                                            "maxLength": 10000
                                          },
                                          "note": {
                                            "type": "string",
                                            "maxLength": 10000
                                          },
                                          "images": {
                                            "maxItems": 20,
                                            "type": "array",
                                            "items": {
                                              "anyOf": [
                                                {
                                                  "type": "object",
                                                  "properties": {
                                                    "url": {
                                                      "type": "string",
                                                      "maxLength": 2000,
                                                      "format": "uri"
                                                    }
                                                  },
                                                  "required": [
                                                    "url"
                                                  ],
                                                  "additionalProperties": false
                                                },
                                                {
                                                  "type": "object",
                                                  "properties": {
                                                    "path": {
                                                      "type": "string",
                                                      "minLength": 1,
                                                      "maxLength": 500
                                                    }
                                                  },
                                                  "required": [
                                                    "path"
                                                  ],
                                                  "additionalProperties": false
                                                }
                                              ]
                                            }
                                          },
                                          "recipe": {
                                            "type": "object",
                                            "properties": {
                                              "servings": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "minutes": {
                                                "type": "number",
                                                "exclusiveMinimum": 0,
                                                "maximum": 999999999.999
                                              },
                                              "steps": {
                                                "maxItems": 100,
                                                "type": "array",
                                                "items": {
                                                  "type": "string",
                                                  "maxLength": 2000
                                                }
                                              }
                                            },
                                            "required": [
                                              "servings",
                                              "steps"
                                            ],
                                            "additionalProperties": false
                                          },
                                          "source": {
                                            "type": "object",
                                            "properties": {
                                              "origin": {
                                                "type": "string",
                                                "enum": [
                                                  "label",
                                                  "restaurant",
                                                  "manual",
                                                  "estimate",
                                                  "ingredients"
                                                ]
                                              },
                                              "by": {
                                                "type": "string",
                                                "const": "chatgpt"
                                              },
                                              "place": {
                                                "type": "string",
                                                "maxLength": 200
                                              },
                                              "description": {
                                                "type": "string",
                                                "maxLength": 2000
                                              },
                                              "edited": {
                                                "type": "boolean"
                                              },
                                              "library": {
                                                "type": "string",
                                                "enum": [
                                                  "splot",
                                                  "off",
                                                  "mine",
                                                  "composition"
                                                ]
                                              },
                                              "key": {
                                                "type": "string",
                                                "maxLength": 200
                                              }
                                            },
                                            "additionalProperties": false
                                          }
                                        },
                                        "additionalProperties": false
                                      },
                                      "copyFrom": {
                                        "type": "object",
                                        "properties": {
                                          "library": {
                                            "type": "string",
                                            "enum": [
                                              "off",
                                              "splot",
                                              "mine",
                                              "composition"
                                            ]
                                          },
                                          "key": {
                                            "type": "string",
                                            "minLength": 1,
                                            "maxLength": 200
                                          }
                                        },
                                        "required": [
                                          "library",
                                          "key"
                                        ],
                                        "additionalProperties": false
                                      }
                                    },
                                    "required": [
                                      "name",
                                      "data"
                                    ],
                                    "additionalProperties": false
                                  },
                                  "portion": {
                                    "type": "object",
                                    "properties": {
                                      "amount": {
                                        "type": "number",
                                        "exclusiveMinimum": 0,
                                        "maximum": 999999999.999
                                      },
                                      "unit": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 100
                                      }
                                    },
                                    "required": [
                                      "amount",
                                      "unit"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "additionalProperties": false
                              }
                            }
                          },
                          "additionalProperties": false
                        },
                        "copyFrom": {
                          "type": "object",
                          "properties": {
                            "library": {
                              "type": "string",
                              "enum": [
                                "off",
                                "splot",
                                "mine",
                                "composition"
                              ]
                            },
                            "key": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 200
                            }
                          },
                          "required": [
                            "library",
                            "key"
                          ],
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "name",
                        "data"
                      ],
                      "additionalProperties": false
                    },
                    "portion": {
                      "type": "object",
                      "properties": {
                        "amount": {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 999999999.999
                        },
                        "unit": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "amount",
                        "unit"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "additionalProperties": false
                },
                "description": "For a recipe: its foods, each with a `portion`."
              }
            },
            "additionalProperties": false,
            "description": "Nutrition, portions and recipe details."
          },
          "copyFrom": {
            "type": "object",
            "properties": {
              "library": {
                "type": "string",
                "enum": [
                  "off",
                  "splot",
                  "mine",
                  "composition"
                ]
              },
              "key": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "library",
              "key"
            ],
            "additionalProperties": false,
            "description": "The food this one was changed from, as `{ \"library\", \"key\" }`, so where it came from is kept."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "To change a food you saved before, its key. Leave out to save a new one."
          }
        },
        "required": [
          "name",
          "data"
        ],
        "additionalProperties": false
      },
      "SettingsChange": {
        "type": "object",
        "properties": {
          "targets": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date",
                "description": "The first day the change applies, usually today. Earlier days keep their targets."
              },
              "through": {
                "type": "string",
                "format": "date",
                "description": "The last day the change applies, inclusive. Leave out to keep it from then on."
              },
              "values": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "caloriesKcal": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 999999999.999,
                        "description": "Energy, in kcal."
                      },
                      "proteinG": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999,
                        "description": "Protein, in grams."
                      },
                      "carbsG": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999,
                        "description": "Carbohydrates, in grams."
                      },
                      "fatG": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999,
                        "description": "Fat, in grams."
                      }
                    },
                    "required": [
                      "caloriesKcal",
                      "proteinG",
                      "carbsG",
                      "fatG"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "All four targets, or `null` to have no targets from `from`."
              }
            },
            "required": [
              "from",
              "values"
            ],
            "additionalProperties": false,
            "description": "A change to your daily targets, from a day on."
          },
          "preferences": {
            "type": "object",
            "properties": {
              "units": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "metric",
                      "imperial",
                      "uk"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The units to show amounts in; `imperial` is US customary. `null` follows the phone."
              },
              "deviceUnits": {
                "type": "string",
                "enum": [
                  "metric",
                  "imperial",
                  "uk"
                ],
                "description": "The units the phone uses, as the app last reported them."
              },
              "showTargets": {
                "type": "boolean",
                "description": "Whether the app shows progress towards your targets."
              },
              "assistantShortcut": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "claude",
                      "chatgpt",
                      "off"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The assistant the app's shortcut opens, or `off`."
              }
            },
            "additionalProperties": false,
            "description": "Display preferences. Only what you send changes; `null` clears a field."
          },
          "body": {
            "type": "object",
            "properties": {
              "weightKg": {
                "anyOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Weight, in kilograms."
              },
              "heightCm": {
                "anyOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Height, in centimetres."
              },
              "age": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 130
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Age, in years."
              },
              "sex": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "female",
                      "male",
                      "unspecified"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Sex, for estimating energy needs."
              },
              "activity": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "sitting",
                      "somewhat",
                      "very"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "How active a usual day is."
              }
            },
            "additionalProperties": false,
            "description": "Body measurements. Only what you send changes; `null` clears a field."
          }
        },
        "additionalProperties": false
      },
      "Meal": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The meal's id."
          },
          "state": {
            "type": "string",
            "enum": [
              "planned",
              "logged"
            ],
            "description": "`logged` for food eaten, `planned` for a meal planned ahead."
          },
          "category": {
            "type": "string",
            "const": "meals",
            "description": "The kind of entry in the journal's timeline: `meals`."
          },
          "day": {
            "type": "string",
            "format": "date",
            "description": "The calendar day it belongs to, in its own timezone."
          },
          "eatenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was eaten, or will be for a plan, in UTC."
          },
          "timezone": {
            "type": "string",
            "description": "The IANA timezone it was eaten in."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Its name, such as Breakfast."
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "Its notes."
          },
          "images": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "url"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Photos: `{ \"path\" }` for photos saved in Splot, `{ \"url\" }` for links."
          },
          "plannedVia": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "app",
                  "api",
                  "chatgpt",
                  "claude",
                  "assistant"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Where it was planned."
          },
          "loggedVia": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "app",
                  "api",
                  "chatgpt",
                  "claude",
                  "assistant"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Where it was logged."
          },
          "nutrition": {
            "type": "object",
            "properties": {
              "caloriesKcal": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "proteinG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "carbsG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "fatG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "saturatedFatG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "sugarsG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "fibreG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              },
              "saltG": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "complete": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "value",
                  "complete"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "caloriesKcal",
              "proteinG",
              "carbsG",
              "fatG",
              "saturatedFatG",
              "sugarsG",
              "fibreG",
              "saltG"
            ],
            "additionalProperties": false,
            "description": "The meal's totals, each `{ \"value\", \"complete\" }`. `complete` is false when an item, or an ingredient of a recipe item, lacks that nutrient."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was created."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it last changed."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MealItem"
            },
            "description": "What was eaten, in order."
          }
        },
        "required": [
          "id",
          "state",
          "category",
          "day",
          "eatenAt",
          "timezone",
          "name",
          "notes",
          "images",
          "plannedVia",
          "loggedVia",
          "nutrition",
          "createdAt",
          "updatedAt",
          "items"
        ],
        "additionalProperties": false
      },
      "MealItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The item's id."
          },
          "position": {
            "type": "integer",
            "description": "Its place in the meal, from 0."
          },
          "quantity": {
            "type": [
              "number",
              "null"
            ],
            "description": "How much was eaten, in `unit`, or null for an entry without a portion."
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "description": "The food's base unit or one of its measures."
          },
          "caloriesKcal": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's energy, in kcal."
          },
          "proteinG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's protein, in grams."
          },
          "carbsG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's carbs, in grams."
          },
          "fatG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's fat, in grams."
          },
          "saturatedFatG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's saturated fat, in grams."
          },
          "sugarsG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's sugars, in grams."
          },
          "fibreG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's fibre, in grams."
          },
          "saltG": {
            "type": [
              "number",
              "null"
            ],
            "description": "The portion's salt, in grams."
          },
          "food": {
            "$ref": "#/components/schemas/Food",
            "description": "The food as it was when the meal was saved."
          }
        },
        "required": [
          "id",
          "position",
          "quantity",
          "unit",
          "caloriesKcal",
          "proteinG",
          "carbsG",
          "fatG",
          "saturatedFatG",
          "sugarsG",
          "fibreG",
          "saltG",
          "food"
        ],
        "additionalProperties": false
      },
      "Food": {
        "type": "object",
        "properties": {
          "library": {
            "type": "string",
            "enum": [
              "off",
              "splot",
              "mine",
              "composition"
            ],
            "description": "The library the food lives in."
          },
          "key": {
            "type": "string",
            "description": "Its key in that library. Send `library` and `key` as `food` to log it."
          },
          "version": {
            "type": "integer",
            "description": "Foods change over time; meals and recipes keep the version they were saved with."
          },
          "name": {
            "type": "string",
            "description": "The food's name."
          },
          "brand": {
            "type": [
              "string",
              "null"
            ],
            "description": "The brand, for packaged products."
          },
          "barcode": {
            "type": [
              "string",
              "null"
            ],
            "description": "The barcode, for packaged products."
          },
          "data": {
            "type": "object",
            "properties": {
              "base": {
                "type": "string",
                "enum": [
                  "g",
                  "ml",
                  "serving"
                ],
                "description": "The unit nutrition is given in."
              },
              "nutrition": {
                "type": "object",
                "properties": {
                  "basisAmount": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999,
                    "description": "How much of the base unit the values are for."
                  },
                  "values": {
                    "type": "object",
                    "properties": {
                      "kcal": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "protein": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "carbs": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "fat": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "saturatedFat": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "sugars": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "fibre": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      },
                      "salt": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999.999
                      }
                    },
                    "additionalProperties": false,
                    "description": "kcal, and grams of protein, carbs, fat, saturated fat, sugars, fibre and salt."
                  }
                },
                "required": [
                  "basisAmount",
                  "values"
                ],
                "additionalProperties": false,
                "description": "Nutrients for `basisAmount` of the base unit, such as per 100 g. A nutrient left out is unknown, not zero."
              },
              "measures": {
                "maxItems": 30,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 100
                    },
                    "size": {
                      "type": "number",
                      "exclusiveMinimum": 0,
                      "maximum": 999999999.999
                    }
                  },
                  "required": [
                    "label",
                    "size"
                  ],
                  "additionalProperties": false
                },
                "description": "Other portions by name, each `{ \"label\", \"size\" }` in the base unit, such as a tablespoon of 15 g."
              },
              "defaultPortion": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "unit": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  }
                },
                "required": [
                  "amount",
                  "unit"
                ],
                "additionalProperties": false,
                "description": "The usual portion, as `{ \"amount\", \"unit\" }`."
              },
              "composition": {
                "type": "string",
                "maxLength": 10000,
                "description": "Ingredients as printed on the label."
              },
              "note": {
                "type": "string",
                "maxLength": 10000,
                "description": "Anything else worth knowing."
              },
              "images": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string",
                          "maxLength": 2000,
                          "format": "uri"
                        }
                      },
                      "required": [
                        "url"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 500
                        }
                      },
                      "required": [
                        "path"
                      ],
                      "additionalProperties": false
                    }
                  ]
                },
                "description": "Photos, as public links or saved Splot photos."
              },
              "recipe": {
                "type": "object",
                "properties": {
                  "servings": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "minutes": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  "steps": {
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 2000
                    }
                  }
                },
                "required": [
                  "servings",
                  "steps"
                ],
                "additionalProperties": false,
                "description": "For a recipe: its `servings`, optional `minutes`, and `steps`."
              },
              "source": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "enum": [
                      "label",
                      "restaurant",
                      "manual",
                      "estimate",
                      "ingredients"
                    ]
                  },
                  "by": {
                    "type": "string",
                    "const": "chatgpt"
                  },
                  "place": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "edited": {
                    "type": "boolean"
                  },
                  "library": {
                    "type": "string",
                    "enum": [
                      "splot",
                      "off",
                      "mine",
                      "composition"
                    ]
                  },
                  "key": {
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "additionalProperties": false,
                "description": "Where the values come from, such as `{ \"origin\": \"label\" }`, or `estimate` with a `description`."
              },
              "ingredients": {
                "type": "array",
                "description": "For a recipe: its foods, each with a `portion`.",
                "items": {
                  "type": "object",
                  "properties": {
                    "food": {
                      "$ref": "#/components/schemas/Food"
                    },
                    "portion": {
                      "type": "object",
                      "properties": {
                        "amount": {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 999999999.999
                        },
                        "unit": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "amount",
                        "unit"
                      ],
                      "additionalProperties": false,
                      "description": "The usual portion, as `{ \"amount\", \"unit\" }`."
                    }
                  },
                  "required": [
                    "food"
                  ]
                }
              },
              "thumbnail": {
                "type": "string",
                "description": "Optional public Storage path for a small food image. Read-only; omit when saving a food."
              }
            },
            "additionalProperties": false,
            "description": "Nutrition, portions and recipe details."
          }
        },
        "required": [
          "library",
          "key",
          "version",
          "name",
          "brand",
          "barcode",
          "data"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "A code naming the error, such as `meal_not_found`."
          },
          "message": {
            "type": "string",
            "description": "What went wrong, in words."
          },
          "issues": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "array",
                  "items": {
                    "type": [
                      "string",
                      "number"
                    ]
                  }
                },
                "message": {
                  "type": "string"
                }
              },
              "required": [
                "path",
                "message"
              ],
              "additionalProperties": false
            },
            "description": "For `invalid_input`: each problem, with the path to the field."
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "MealPage": {
        "type": "object",
        "properties": {
          "meals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Meal"
            },
            "description": "The page of meals, newest first."
          },
          "nextOffset": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The offset of the next page, or null on the last."
          }
        },
        "required": [
          "meals",
          "nextOffset"
        ],
        "additionalProperties": false
      },
      "FoodPage": {
        "type": "object",
        "properties": {
          "foods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Food"
            },
            "description": "The page of foods."
          },
          "nextOffset": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The offset of the next page, or null on the last."
          }
        },
        "required": [
          "foods",
          "nextOffset"
        ],
        "additionalProperties": false
      },
      "Settings": {
        "type": "object",
        "properties": {
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "startsOn": {
                  "type": "string",
                  "format": "date",
                  "description": "The first day of the period."
                },
                "values": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "caloriesKcal": {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "maximum": 999999999.999,
                          "description": "Energy, in kcal."
                        },
                        "proteinG": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999.999,
                          "description": "Protein, in grams."
                        },
                        "carbsG": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999.999,
                          "description": "Carbohydrates, in grams."
                        },
                        "fatG": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999.999,
                          "description": "Fat, in grams."
                        }
                      },
                      "required": [
                        "caloriesKcal",
                        "proteinG",
                        "carbsG",
                        "fatG"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The targets in the period, or `null` for none."
                }
              },
              "required": [
                "startsOn",
                "values"
              ],
              "additionalProperties": false
            },
            "description": "Your daily targets over time, oldest first. Each period applies from `startsOn` until the next one."
          },
          "preferences": {
            "type": "object",
            "properties": {
              "units": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "metric",
                      "imperial",
                      "uk"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The units to show amounts in; `imperial` is US customary. `null` follows the phone."
              },
              "deviceUnits": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "metric",
                      "imperial",
                      "uk"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The units the phone uses, as the app last reported them."
              },
              "showTargets": {
                "type": "boolean",
                "description": "Whether the app shows progress towards your targets."
              },
              "assistantShortcut": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "claude",
                      "chatgpt",
                      "off"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The assistant the app's shortcut opens, or `off`."
              }
            },
            "required": [
              "units",
              "deviceUnits",
              "showTargets",
              "assistantShortcut"
            ],
            "additionalProperties": false,
            "description": "Display preferences."
          },
          "body": {
            "type": "object",
            "properties": {
              "weightKg": {
                "anyOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Weight, in kilograms."
              },
              "heightCm": {
                "anyOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 999999999.999
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Height, in centimetres."
              },
              "age": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 130
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Age, in years."
              },
              "sex": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "female",
                      "male",
                      "unspecified"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Sex, for estimating energy needs."
              },
              "activity": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "sitting",
                      "somewhat",
                      "very"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "How active a usual day is."
              }
            },
            "required": [
              "weightKg",
              "heightCm",
              "age",
              "sex",
              "activity"
            ],
            "additionalProperties": false,
            "description": "Body measurements, each `null` until set."
          }
        },
        "required": [
          "targets",
          "preferences",
          "body"
        ],
        "additionalProperties": false
      },
      "FoodCorrection": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The correction's id."
          },
          "foodId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "description": "Your food the change was made in, or `null` once that food is deleted."
          },
          "product": {
            "type": "object",
            "properties": {
              "library": {
                "type": "string",
                "enum": [
                  "splot",
                  "off"
                ],
                "description": "The library the product is in."
              },
              "key": {
                "type": "string",
                "description": "The product's key in that library."
              }
            },
            "required": [
              "library",
              "key"
            ],
            "additionalProperties": false,
            "description": "The catalogue product the change is for."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "accepted",
              "rejected",
              "superseded"
            ],
            "description": "`pending` until reviewed, then `accepted` or `rejected`; `superseded` when a later change to the same food replaced it."
          },
          "original": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {},
            "description": "The product as it was: `name`, `brand`, `barcode`, `base`, `measures`, `composition`, and `nutrition` per one base unit, such as per gram."
          },
          "proposal": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {},
            "description": "Only the fields you changed, in the same form, with their new values."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When you made the change."
          },
          "reviewedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was reviewed, or `null` while pending."
          },
          "reviewNote": {
            "type": [
              "string",
              "null"
            ],
            "description": "A note from the review, if any."
          }
        },
        "required": [
          "id",
          "foodId",
          "product",
          "status",
          "original",
          "proposal",
          "createdAt",
          "reviewedAt",
          "reviewNote"
        ],
        "additionalProperties": false
      },
      "CorrectionPage": {
        "type": "object",
        "properties": {
          "corrections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FoodCorrection"
            },
            "description": "The page of corrections, newest first."
          },
          "nextOffset": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The offset of the next page, or null on the last."
          }
        },
        "required": [
          "corrections",
          "nextOffset"
        ],
        "additionalProperties": false
      }
    },
    "responses": {
      "InvalidInput": {
        "description": "The body or query is invalid; `issues` says which fields. Or the body is not valid JSON.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The key is missing, revoked or expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key's permission doesn't allow this request, or you haven't yet agreed to how Splot handles health information.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests. Wait for `Retry-After` seconds.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "description": "Seconds until the limit resets.",
            "schema": {
              "type": "integer"
            }
          }
        }
      }
    }
  }
}