Create a Custom Dish from Scratch with a Manual Intake

Create a one-off food intake directly from ingredient IDs and quantities, without selecting an existing LogMeal dish.

What You’ll Build

You’ll implement an ingredient-to-intake flow where your app retrieves ingredients from the LogMeal dataset, lets the user select ingredients and quantities, and creates a manual intake without providing a dish id.

This pattern is useful when the meal does not match an existing LogMeal dish, when the user wants to describe a personal recipe, or when a professional needs to record a custom meal precisely from its ingredients.

This workflow creates a one-off food item inside the intake. It does not create a reusable Custom Recipe with its own catalog dish ID, although users can choose to create a Favorite intake for personal future reuse.


Prerequisites

  • Plan: Monitor and above (see more info about LogMeal Plans)
  • User type: 🔴 APIUser or 🔵 APIUserManager (see more info about User Types)
  • A valid target userId
  • Valid ingredientId values retrieved from the LogMeal ingredient dataset
  • Client library for HTTP (e.g., Python requests, Node axios, Java OkHttp)

How Ingredient-Only Manual Intakes Work

Each item in the dishes array references an existing LogMeal dish through its id.

When you wish to submit an ingredient-only manual intake, you may instead:

  1. Omit the dish id.
  2. Provide a non-empty ingredients list.
  3. Identify each ingredient using a valid ingredientId.
  4. Optionally provide ingredientAmount, measureSystem, and measureId.
  5. Optionally provide the total item quantity so ingredient weights are scaled proportionally.
  6. Optionally provide a non-empty item-level name to label this ingredient-only food item.
  7. Optionally provide a root-level intake_name as an independent label for the complete intake.

The ingredient recipe is used to calculate:

  • the total serving size;
  • ingredient-derived food groups;
  • nutritional information for the intake and each food item;
  • image-level and per-item Nutri-Score;
  • metric and preferred measures.

Catalog identifiers remain null because no catalog dish was selected. When an item-level name is supplied, the same submitted text is returned in the corresponding foodName and recipe_per_item[].name positions. The text is not translated or matched against the dish catalog.


Sequence Diagram

Main Flow (Ingredients Selection + Manual Intake Creation)

sequenceDiagram
  participant User
  participant App
  participant LogMeal API

  App->>LogMeal API: GET /v2/dataset/ingredients
  LogMeal API-->>App: 200 OK (ingredient IDs, names, measures)
  App-->>User: Show ingredient search and quantity controls
  User->>App: Select ingredients and quantities
  App->>LogMeal API: POST /v2/intake/manualInput/{userId} <br> (dishes without id)
  LogMeal API-->>App: 201 Created (new intake)
  App->>LogMeal API: GET /v2/intake/{imageId}
  LogMeal API-->>App: 200 OK (recipe, serving size, food groups, nutrition, Nutri-Score)
  App-->>User: Custom intake saved ✅

Optional Nutrition Preview

sequenceDiagram
  participant User
  participant App
  participant LogMeal API

  User->>App: Edit ingredients or quantities
  App->>LogMeal API: POST /v2/nutrition/recipe/compute_nutrients
  LogMeal API-->>App: 200 OK (calculated nutritional information)
  App-->>User: Refresh nutrition preview

Implementation Guide

1. Retrieve Available Ingredients

Call GET /dataset/ingredients and let the user search or select ingredients from the returned dataset.

Use the returned ingredient IDs in the ingredientId fields of the manual-intake request.

2. Build the Manual-Intake Request

Do not include an id for an ingredient-only item. Instead, provide its ingredients array:

{
  "intake_name": "Friday lunch",
  "dishes": [
    {
      "name": "Cod with orange",
      "ingredients": [
        {
          "ingredientId": 388,
          "ingredientAmount": 100
        },
        {
          "ingredientId": 539,
          "ingredientAmount": 240
        }
      ],
      "quantity": 340
    }
  ],
  "timestamp": "2026/06/18, 07:55:00"
}

Call:

POST /v2/intake/manualInput/USERID

The root-level intake_name labels the complete intake. The dishes[].name field labels one ingredient-only item. They are independent values.

3. Retrieve the Complete Intake

Use the returned intake identifier to call GET /intake/{imageId}.

For the ingredient-only item, expect catalog identifier fields to remain null while the submitted item name is preserved:

{
  "intake_name": "Friday lunch",
  "foodName": ["Cod with orange"],
  "ids": [null],
  "foodGroup": [
    "fruit",
    "fish"
  ],
  "hasNutritionalInfo": true,
  "image_nutri_score": {
    "nutri_score_category": "A",
    "nutri_score_standardized": 81
  },
  "recipe_per_item": [
    {
      "dish_id": null,
      "name": "Cod with orange",
      "serving_size": 340,
      "foodGroups": [
        {
          "id": 6,
          "name": "fruit"
        },
        {
          "id": 9,
          "name": "fish"
        }
      ]
    }
  ],
  "nutritional_info_per_item": [
    {
      "id": null,
      "hasNutritionalInfo": true,
      "hasNutriScore": true,
      "nutri_score": {
        "nutri_score_category": "A",
        "nutri_score_standardized": 81
      },
      "serving_size": 340
    }
  ]
}

User Interaction Recommendations

  • Let users search ingredients by name and store their selected ingredientId values.
  • Submit ingredient amounts in grams, even if another preferred display measure is selected.
  • Show the running total weight and optionally preview nutritional information before submission.
  • Use dishes[].name to display a meaningful label for each ingredient-only item.
  • Use the independent root-level intake_name when the complete intake also needs a label, such as "Friday lunch".
  • Clearly distinguish one-off ingredient-based items from reusable Custom Recipes.
  • Allow users to edit the intake name later through the modify-name endpoint.

Related Endpoints

Use the following endpoints to build an ingredient-based manual intake and retrieve its calculated results:

Optional preview and reporting helpers:

Optional reuse and maintenance helpers:

Remember to check applicable request limitations inside each endpoint.


Common Pitfalls & Tips

  • Missing recipe: when id is omitted, provide a non-empty ingredients list.
  • Invalid ingredients: use valid ingredientId values returned by the LogMeal ingredient dataset.
  • Ingredient amounts: ingredientAmount is expressed in grams.
  • Name placement: use root-level intake_name for the complete intake and dishes[].name for one ingredient-only item.
  • Invalid item names: when dishes[].name is supplied, it must be a non-empty string.
  • Catalog name protection: a dishes[].name supplied together with a valid dish id is ignored for naming; the catalog-derived name is returned.
  • Null catalog fields: ids and dish_id remain null for ingredient-only items. foodName and the per-item name are null only when dishes[].name is omitted.
  • One-off item: this flow does not create a reusable catalog dish or Custom Recipe. Although the user might choose to save it as a Favorite intake to reuse later.

Optional Enhancements

  • Preview nutrition before submission while the user edits ingredient quantities.
  • Create a reusable personal Favorite intake item to simplify repeated entries.
  • Create a reusable company-level Custom Recipe when the same custom dish will be used repeatedly.
  • Add item-level names for ingredient-only entries and an independent whole-intake name when useful.
  • Retrieve the saved intake from history and display ingredient-derived food groups, nutrition, and Nutri-Score.

Next Steps

Pick your path based on what you want to build next:


Did this page help you?