---
title: "Create a meal"
method: POST
path: "/meals"
tags: ["Meals"]
---

# Create a meal

`POST /meals`

## Request

- Base URL: `https://app.splot.health/v1`
- URL: `https://app.splot.health/v1/meals`
- Auth: HTTP bearer

Logs a meal you ate, or plans one ahead.

## Request body

- MealInput
  - `state` 'planned' | 'logged': Whether the meal was eaten or is planned ahead.
  - `images` union[]: Photos: public links as `{ "url" }`, or saved Splot photos as `{ "path" }` from an earlier read.
    - union
      - object
        - `url` string, uri, required
      - object
        - `path` string, required
  - `eatenAt` string, date-time, required: When it was eaten, or will be for a plan, with a UTC offset.
  - `timezone` string, required: The IANA timezone it is eaten in, such as `Europe/Berlin`.
  - `name` string, nullable: A name, such as Breakfast.
  - `notes` string, nullable: Notes about the meal.
  - `items` object[], required: What was eaten.
    - `food` object: A food that exists: its `library` and `key` from a food search.
      - `library` 'off' | 'splot' | 'mine' | 'composition', required: The library the food is in.
      - `key` string, required: The food's key in that library.
      - `version` integer: Only to keep the version a saved meal already has. Leave out to use the food as it is now.
    - `newFood` NewFood
      - `name` string, required: The food's name.
      - `brand` string, nullable: The brand, for a packaged product.
      - `barcode` string, nullable: The barcode: 8 to 14 digits.
      - `data` object, required: Nutrition, portions and recipe details.
        - `base` 'g' | 'ml' | 'serving': The unit nutrition is given in.
        - `nutrition` object: Nutrients for `basisAmount` of the base unit, such as per 100 g. A nutrient left out is unknown, not zero.
          - `basisAmount` number, required: How much of the base unit the values are for.
          - `values` object, required: kcal, and grams of protein, carbs, fat, saturated fat, sugars, fibre and salt. Carbs exclude fibre, as EU labels give them; subtract fibre from a US label's total carbohydrate.
            - `kcal` number
            - `protein` number
            - `carbs` number
            - `fat` number
            - `saturatedFat` number
            - `sugars` number
            - `fibre` number
            - `salt` number
        - `measures` object[]: Other portions by name, each `{ "label", "size" }` in the base unit, such as a tablespoon of 15 g.
          - `label` string, required
          - `size` number, required
        - `defaultPortion` object: The usual portion, as `{ "amount", "unit" }`.
          - `amount` number, required
          - `unit` string, required
        - `composition` string: Ingredients as printed on the label.
        - `note` string: Anything else worth knowing.
        - `images` union[]: Photos, as public links or saved Splot photos.
          - union
            - object
              - …
            - object
              - …
        - `recipe` object: For a recipe: its `servings`, optional `minutes`, `steps`, and optional `weight`: the whole recipe's weight once made, in grams. With a weight the recipe is stored per 100 g; without one, a `g` measure is estimated from the ingredients when all of them have a weight in grams.
          - `servings` number, required
          - `minutes` number
          - `steps` string[], required
          - `weight` number
        - `source` object: Where the values come from, such as `{ "origin": "label" }`, or `estimate` with a `description`.
          - `origin` 'label' | 'restaurant' | 'manual' | 'estimate' | 'ingredients'
          - `by` 'chatgpt'
          - `place` string
          - `description` string
          - `edited` boolean
          - `library` 'splot' | 'off' | 'mine' | 'composition'
          - `key` string
        - `ingredients` object[]: For a recipe: its foods, each with a `portion`.
          - `food` object
            - `library` 'off' | 'splot' | 'mine' | 'composition', required
            - `key` string, required
            - `version` integer
          - `newFood` object
            - `name` string, required
            - `brand` string, nullable
            - `barcode` string, nullable
            - `data` object, required
              - …
            - `copyFrom` object
              - …
          - `portion` object
            - `amount` number, required
            - `unit` string, required
      - `copyFrom` object: The food this one was changed from, as `{ "library", "key" }`, so where it came from is kept.
        - `library` 'off' | 'splot' | 'mine' | 'composition', required
        - `key` string, required
    - `quantity` number, nullable: How much was eaten, in `unit`. Send it with `unit`, or leave both out.
    - `unit` string, nullable: The food's base unit (`g`, `ml` or `serving`) or one of its measures.
    - `variety` string, nullable

## Response `201`

The new meal.

- Meal
  - `id` string, uuid, required: The meal's id.
  - `state` 'planned' | 'logged', required: `logged` for food eaten, `planned` for a meal planned ahead.
  - `category` 'meals', required: The kind of entry in the journal's timeline: `meals`.
  - `day` string, date, required: The calendar day it belongs to, in its own timezone.
  - `eatenAt` string, date-time, required: When it was eaten, or will be for a plan, in UTC.
  - `timezone` string, required: The IANA timezone it was eaten in.
  - `name` string, nullable, required: Its name, such as Breakfast.
  - `notes` string, nullable, required: Its notes.
  - `images` union[], required: Photos: `{ "path" }` for photos saved in Splot, `{ "url" }` for links.
    - union
      - object
        - `url` string, required
      - object
        - `path` string, required
  - `plannedVia` 'app' | 'api' | 'chatgpt' | 'claude' | 'assistant', nullable, required: Where it was planned.
  - `loggedVia` 'app' | 'api' | 'chatgpt' | 'claude' | 'assistant', nullable, required: Where it was logged.
  - `nutrition` object, required: The meal's totals, each `{ "value", "complete" }`. `complete` is false when an item, or an ingredient of a recipe item, lacks that nutrient.
    - `caloriesKcal` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `proteinG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `carbsG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `fatG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `saturatedFatG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `sugarsG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `fibreG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
    - `saltG` object, required
      - `value` number, nullable, required
      - `complete` boolean, required
  - `createdAt` string, date-time, required: When it was created.
  - `updatedAt` string, date-time, required: When it last changed.
  - `items` MealItem[], required: What was eaten, in order.
    - `id` string, uuid, required: The item's id.
    - `position` integer, required: Its place in the meal, from 0.
    - `quantity` number, nullable, required: How much was eaten, in `unit`, or null for an entry without a portion.
    - `unit` string, nullable, required: The food's base unit or one of its measures.
    - `caloriesKcal` number, nullable, required: The portion's energy, in kcal.
    - `proteinG` number, nullable, required: The portion's protein, in grams.
    - `carbsG` number, nullable, required: The portion's carbs, in grams.
    - `fatG` number, nullable, required: The portion's fat, in grams.
    - `saturatedFatG` number, nullable, required: The portion's saturated fat, in grams.
    - `sugarsG` number, nullable, required: The portion's sugars, in grams.
    - `fibreG` number, nullable, required: The portion's fibre, in grams.
    - `saltG` number, nullable, required: The portion's salt, in grams.
    - `variety` string, nullable, required: For a common food, which of its varieties it was, such as `gala`, or null.
    - `food` Food, required
      - `library` 'off' | 'splot' | 'mine' | 'composition', required: The library the food lives in.
      - `key` string, required: Its key in that library. Send `library` and `key` as `food` to log it.
      - `version` integer, required: Foods change over time; meals and recipes keep the version they were saved with.
      - `name` string, required: The food's name.
      - `brand` string, nullable, required: The brand, for packaged products.
      - `barcode` string, nullable, required: The barcode, for packaged products.
      - `data` object, required: Nutrition, portions and recipe details.
        - `base` 'g' | 'ml' | 'serving': The unit nutrition is given in.
        - `nutrition` object: Nutrients for `basisAmount` of the base unit, such as per 100 g. A nutrient left out is unknown, not zero.
          - `basisAmount` number, required: How much of the base unit the values are for.
          - `values` object, required: kcal, and grams of protein, carbs, fat, saturated fat, sugars, fibre and salt. Carbs exclude fibre, as EU labels give them; subtract fibre from a US label's total carbohydrate.
            - `kcal` number
            - `protein` number
            - `carbs` number
            - `fat` number
            - `saturatedFat` number
            - `sugars` number
            - `fibre` number
            - `salt` number
        - `measures` object[]: Other portions by name, each `{ "label", "size" }` in the base unit, such as a tablespoon of 15 g.
          - `label` string, required
          - `size` number, required
        - `defaultPortion` object: The usual portion, as `{ "amount", "unit" }`.
          - `amount` number, required
          - `unit` string, required
        - `composition` string: Ingredients as printed on the label.
        - `note` string: Anything else worth knowing.
        - `images` union[]: Photos, as public links or saved Splot photos.
          - union
            - object
              - …
            - object
              - …
        - `recipe` object: For a recipe: its `servings`, optional `minutes`, `steps`, and optional `weight`: the whole recipe's weight once made, in grams. With a weight the recipe is stored per 100 g; without one, a `g` measure is estimated from the ingredients when all of them have a weight in grams.
          - `servings` number, required
          - `minutes` number
          - `steps` string[], required
          - `weight` number
        - `source` object: Where the values come from, such as `{ "origin": "label" }`, or `estimate` with a `description`.
          - `origin` 'label' | 'restaurant' | 'manual' | 'estimate' | 'ingredients'
          - `by` 'chatgpt'
          - `place` string
          - `description` string
          - `edited` boolean
          - `library` 'splot' | 'off' | 'mine' | 'composition'
          - `key` string
        - `ingredients` object[]: For a recipe: its foods, each with a `portion`.
          - `food` Food, required (recursive)
          - `portion` object: The usual portion, as `{ "amount", "unit" }`.
            - `amount` number, required
            - `unit` string, required
        - `thumbnail` string: Optional public Storage path for a small food image. Read-only; omit when saving a food.
      - `common` object: For a common food such as Apple, which form this is (raw, baked, dried) and its other forms.
        - `id` string, required: The common food's id, such as `apple`.
        - `name` string, required: The common food's name.
        - `names` object: Its name in each language, by language code, such as `{"en": "Apple", "pl": "Jabłko"}`.
        - `form` string, required: The id of the form this food is.
        - `forms` object[], required: Every form, in order, each a composition food: send `library` `composition` and its `key` to log it.
          - `id` string, required
          - `name` string, required
          - `key` string, required
          - `version` integer, required
          - `food` object
        - `varieties` object[]: Its varieties, each with its parent, as a tree: Red, then Crimson Seedless under it. Send one as a meal item's `variety`.
          - `id` string, required
          - `name` string, required
          - `names` object
          - `parent` string, nullable, required
        - `plural` string, nullable: The food's plural, such as `apples`.
        - `plurals` object: Its plural in each language.
        - `portionNames` object: Each portion label in `data.measures` named in other languages, such as `{"cup": {"pl": "szklanka"}}`. Send the label itself as a meal item's `unit`.

## Other responses

- `400`: The body or query is invalid; `issues` says which fields. Or the body is not valid JSON.
- `401`: The key is missing, revoked or expired.
- `403`: The key's permission doesn't allow this request, or you haven't yet agreed to how Splot handles health information.
- `404`: A food the meal points at doesn't exist.
- `409`: A new food has a barcode the catalogue already knows.
- `429`: Too many requests. Wait for `Retry-After` seconds.

---

[API](https://skmtc.dev/splot/apis/splot-api.md) · [All operations](https://skmtc.dev/splot/apis/splot-api/llms.txt) · [OpenAPI document](https://skmtc.dev/splot/apis/splot-api/revisions/02f2a6340fe9?raw)
