Meals and diary API

Log meals from a draft, a photo, text or a barcode; read and fix the diary. 21 ops: log_meal, get_day, get_meal, list_review_queue, update_meal, confirm_ingredients, reject_ingredients, add_ingredients, set_nutrients, mark_reviewed, delete_meal, copy_meal, save_personal_food, list_personal_foods, ar

Log meals from a draft, a photo, text or a barcode; read and fix the diary.

Log a meal · POST /api/v1/log_meal · scope meals:write

Log what the person ate. It is always stored; nothing is lost when you are unsure. In chat, YOU look at the photo or read the message and send items (a draft): free and unlimited. Other inputs, exactly one per call: text (simple text is free; anything harder is one analysis on our model, Plus), image (our model reads a photo, one analysis, Plus: in chat read it yourself instead), barcode (+ servings; free), recipe (ingredients and amounts of a home dish; free). How to fill the draft: - One item per distinct food or drink ("grilled chicken breast", "white rice", "oat milk latte"), named as a menu or label would. A dish served as one thing (a burrito, a sandwich, a smoothie) is one item; its parts are its ingredients. - Amount: grams when you can estimate them (plate ≈ 26 cm, fork ≈ 19 cm, palm of meat ≈ 100 g, fist of rice ≈ 150 g), else portion {quantity, unit} ("1 cup", "2 slice", "1 medium"). For a package with a barcode, send barcode and servings instead. - confidence (what it is) and portion_confidence (how much), 0–1: 0.9+ you can see it clearly or were told; 0.7 typical guess; 0.5 hard to tell. - ingredients: what is in the item, each with a confidence, most certain first. · ≥ 0.85: visible or stated ("eggs" in scrambled eggs). · 0.60–0.85: standard for this dish though not visible (cheese in a quesadilla, rice in sushi). · 0.30–0.60: plausible but hidden. Always consider cooking fat (butter, oil), added sugar, onion and garlic in sauces, dressings and soups: they matter for calories and for gut symptoms, and the person is asked about them. · below 0.30: leave it out. - cooking_method when you can tell (grilled, pan_fried, roasted…). Copy any label or ingredient list text you can read into label_text, verbatim. - Never invent a barcode or brand you cannot read. Examples: 1. Photo of scrambled eggs on toast with a coffee → {"items":[{"name":"scrambled eggs","grams":120,"confidence":0.9,"portion_confidence":0.7,"cooking_method":"pan_fried","ingredients":[{"name":"eggs","confidence":0.97,"visible":true},{"name":"butter","confidence":0.5},{"name":"milk","confidence":0.35}]},{"name":"sourdough toast","portion":{"quantity":1,"unit":"slice"},"confidence":0.85,"ingredients":[{"name":"wheat flour","confidence":0.9}]},{"name":"black coffee","grams":240,"confidence":0.8}]} 2. "Chipotle bowl: chicken, white rice, black beans, mild salsa, no cheese" → {"title":"Chipotle bowl","items":[{"name":"chicken burrito bowl","grams":520,"confidence":0.85,"portion_confidence":0.6,"ingredients":[{"name":"chicken","confidence":0.95},{"name":"white rice","confidence":0.95},{"name":"black beans","confidence":0.95},{"name":"tomato salsa","confidence":0.9},{"name":"onion","confidence":0.7},{"name":"garlic","confidence":0.45}]}]} 3. A granola bar wrapper with a readable barcode → {"items":[{"name":"granola bar","barcode":"0123456789012","servings":1}]} We match each item against the person's own foods, the barcode index, the food database, then recipes; portion it; compute calories and nutrients; and tier ingredients: confirmed (≥0.85 or from a label), likely (0.60–0.85, counted), possible (0.30–0.60, not counted, asked about). needs_review is set under the person's threshold (default 0.80), when a possible ingredient is one of their triggers or allergens, or when a portion is over 3× typical. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is. Then answer with confirm_ingredients / reject_ingredients by id; fix amounts with update_meal.

curl -X POST https://getgutlog.com/api/v1/log_meal \  -H "Authorization: Bearer gutlog_…"

Get a diary day · POST /api/v1/get_day · scope meals:read or GET …?input=

One day of the food diary in the person's timezone: every meal with its items (match, grams, nutrients, confidence) and ingredients (id, tier, confidence, status), the day's nutrient totals, the person's daily goals and how many meals need review. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; totals_display and goals_display have kcal and grams. Defaults to today.

curl -X POST https://getgutlog.com/api/v1/get_day \  -H "Authorization: Bearer gutlog_…"

Get a meal · POST /api/v1/get_meal · scope meals:read or GET …?input=

One logged meal with everything an edit needs: item ids, ingredient ids, tiers, statuses and the open questions. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/get_meal \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'

List meals to review · POST /api/v1/list_review_queue · scope meals:read or GET …?input=

Meals flagged needs_review (low confidence, a possible trigger or allergen, an implausible portion), newest first, each as a full meal with its questions. Go through them with the person: ask the questions, then confirm_ingredients / reject_ingredients, update_meal for amounts, or mark_reviewed when a meal looks right.

curl -X POST https://getgutlog.com/api/v1/list_review_queue \  -H "Authorization: Bearer gutlog_…"

Update a meal · POST /api/v1/update_meal · scope meals:write

Change a logged meal: its title, type, time or note; per item (meal_item_id from the meal) its grams or household portion ("the chicken was more like 200 g"), its match (food_id from search_foods: "it was oat milk"), its name, or remove it; add_items with the same item shape as log_meal. Edits win over estimates and are kept as corrections. To change a single number directly use set_nutrients. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/update_meal \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'

Confirm ingredients · POST /api/v1/confirm_ingredients · scope meals:write

The person says these ingredients were in the meal ("yes, butter"): ids from the meal's ingredients or questions, or all_likely: true with meal_id to confirm every likely one at once ("yes, that's right"). A confirmed possible ingredient starts counting (a hidden fat or sugar adds its calories). Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/confirm_ingredients \  -H "Authorization: Bearer gutlog_…"

Reject ingredients · POST /api/v1/reject_ingredients · scope meals:write

The person says these ingredients were not in the meal ("no cheese", "no garlic"): ids from the meal's ingredients or questions. A rejected ingredient no longer counts toward nutrients or gut exposures. If the numbers should drop too (the cheese was part of the matched dish), also set_nutrients or swap the match with update_meal. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/reject_ingredients \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"ids":["6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"]}'

Add ingredients · POST /api/v1/add_ingredients · scope meals:write

Add ingredients we missed to one item ("it had onions", "cooked in butter"), confirmed. A hidden fat or sugar adds its usual amount's calories. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/add_ingredients \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_item_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","ingredients":[{"name":"scrambled eggs"}]}'

Set nutrient values · POST /api/v1/set_nutrients · scope meals:write

Override nutrient values of one item directly ("the protein was more like 45 g", "it said 320 kcal"). Values are in display units: kcal for energy, grams for macros, mg for sodium and other minerals, µg (ug) for vitamins A, D, B12 and folate, unless unit says otherwise. Each field set is locked: later portion changes keep it. value null unlocks a field back to the estimate. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/set_nutrients \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_item_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","set":[{"nutrient":"nutrient","value":0}]}'

Mark a meal reviewed · POST /api/v1/mark_reviewed · scope meals:write

The person looked at the meal and it is right as it is: it leaves the review queue and stays out. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/mark_reviewed \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'

Delete a meal · POST /api/v1/delete_meal · scope meals:write

Remove a meal from the diary (logged twice, or never eaten). It no longer counts toward totals, the review queue or gut analysis. Confirm with the person first.

curl -X POST https://getgutlog.com/api/v1/delete_meal \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'

Copy a meal · POST /api/v1/copy_meal · scope meals:write

Log a meal again ("same as yesterday's breakfast"): meal_id, or date + meal_type for the latest meal of that type that day. Logged now unless eaten_at is given; as_meal_type changes its type. Free. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.

curl -X POST https://getgutlog.com/api/v1/copy_meal \  -H "Authorization: Bearer gutlog_…"

Save as my usual · POST /api/v1/save_personal_food · scope meals:write

Save a corrected item (meal_item_id) or a whole meal (meal_id, with a name) as one of the person's own foods: "save this as my usual latte". Next time that name matches first, with these exact nutrients and ingredients. Saving under an existing name updates it. Items corrected on three different meals are saved automatically.

curl -X POST https://getgutlog.com/api/v1/save_personal_food \  -H "Authorization: Bearer gutlog_…"

List personal foods · POST /api/v1/list_personal_foods · scope meals:read or GET …?input=

The person's own foods (saved as usual or learned from corrections), most used first, with nutrients per 100 g, default grams and ingredients. Log one by its name, or with food_id "personal:<id>" in a log_meal item.

curl -X POST https://getgutlog.com/api/v1/list_personal_foods \  -H "Authorization: Bearer gutlog_…"

Archive a personal food · POST /api/v1/archive_personal_food · scope meals:write

Stop matching a personal food (it was wrong, or the person no longer eats it). Meals already logged with it keep their numbers.

curl -X POST https://getgutlog.com/api/v1/archive_personal_food \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"personal_food_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'

Rate an analysis · POST /api/v1/rate_analysis · scope meals:write

Thumbs up or down on how well a meal was analyzed, with an optional reason in the person's words. One rating per person per meal; rating again replaces it. Ask what was wrong after a thumbs down and fix it with the edit ops.

curl -X POST https://getgutlog.com/api/v1/rate_analysis \  -H "Authorization: Bearer gutlog_…" \  -H "Content-Type: application/json" \  -d '{"meal_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","rating":"up"}'

Get confidence calibration · POST /api/v1/get_calibration · scope meals:read or GET …?input=

How well ingredient confidences match what the person confirmed and rejected: per 0.1 bucket and source (photo, text, database), how many were answered, the confirm rate and the gap from the bucket's midpoint. A well calibrated 0.8 bucket confirms about 80%.

curl -X POST https://getgutlog.com/api/v1/get_calibration \  -H "Authorization: Bearer gutlog_…"

Get calibration across everyone · POST /api/v1/get_calibration_all · scope meals:read or GET …?input=

Calibration across every organization (counts only), for tuning thresholds and the analysis prompt. Gutlog staff only.

curl -X POST https://getgutlog.com/api/v1/get_calibration_all \  -H "Authorization: Bearer gutlog_…"

Refresh shared aliases · POST /api/v1/refresh_global_aliases · scope meals:write

Promote correction patterns seen from at least 20 different people to shared aliases (and drop ones that fell under). Runs daily on its own; staff only. Only the pattern and a count are kept, never who.

curl -X POST https://getgutlog.com/api/v1/refresh_global_aliases \  -H "Authorization: Bearer gutlog_…"

Get logging settings · POST /api/v1/get_logging_settings · scope meals:read or GET …?input=

The person's review threshold (meals under it are flagged) and daily nutrient goals (integers; goals_display in kcal and grams). Goals default to the FDA Daily Values for 2,000 kcal until set.

curl -X POST https://getgutlog.com/api/v1/get_logging_settings \  -H "Authorization: Bearer gutlog_…"

Update logging settings · POST /api/v1/update_logging_settings · scope meals:write

Set the review threshold (0–1; lower flags fewer meals) and daily goals in display units: {"energy": 1800, "protein": 120, "sodium": 2000} (kcal, grams, mg). null removes a goal.

curl -X POST https://getgutlog.com/api/v1/update_logging_settings \  -H "Authorization: Bearer gutlog_…"