Set Recipe Ingredients
④ of 5 | Requires: ③ createRecipe | Next: ⑤ addRecipeServing
Save the full ingredient list for a recipe in one commit — add, edit, delete, and reorder are all expressed as the complete ordered list you send. Each item is a structured form or resolution row; there is no free-text parsing on this path.
The list is discriminated by source:
• form — a structured search → pick → quantity row. Omit id for a new row (the server mints one) or send an existing irow_... id to edit/reorder it.
• resolution — an existing row born from the resolve workflow. It must carry an existing irow_... id; immutable lineage is inherited server-side and cannot be supplied by the client.
ingredients_entry_method must equal the recipe's locked entry method. A recipe locked to form rejects any resolution row.
position is taken verbatim, so drag-reorder is a resend with the new positions. An empty items list deletes all ingredients.
On success, recipe-level nutrition (L1) and any existing per-serving panels (L2) are recomputed atomically in the same commit.
Next: ⑤ addRecipeServing — add a serving size to generate the final nutrition facts label.
recipe_id*Recipe IdIf-Match*stringThe recipe's current version_id: the one the last change to this recipe returned, or the one reading the recipe returns (get_recipe). A stale value is refused with the current version_id; read the recipe again and retry.
application/json- body
Full-list save: add / edit / delete / reorder in one commit.
ingredients_entry_method*Ingredients Entry MethodMust equal the recipe's locked entry method.
"resolution""form"items*array<||>The complete ordered ingredient list (empty = delete all).
0 <= itemsSuccessful Response
application/json- response
Response for update ingredients endpoint.
data*Data payload for update ingredients response.
meta*Response metadata.
version_id?|Version committed for this mutation; pass on the next request as If-Match for optimistic concurrency. Present only on versions declaring the recipe_versioning capability.
curl -X POST 'https://api.bettermenu.live/studio/recipes/string/ingredients' \ -H 'If-Match: string' \ -H 'Content-Type: application/json' \ -d '{ "ingredients_entry_method": "resolution", "items": []}'{ "data": { "recipe_id": "string", "resolution_id": "string", "ingredients": [ { "id": "string", "position": 0, "selected_ingredient_id": "string", "selected_ingredient_name": "string", "display_name": "string", "metric_quantity_g": 0, "search_provenance": "system_matched", "unit_conversion_provenance": "identity", "source": "resolution", "original_text": "string", "parsed_quantity": 0, "parsed_unit": "string", "parsed_ingredient_name": "string", "portion_id": "string" } ], "ingredient_conversions": [ { "conversion_source": "string", "reasoning": "string", "portion_reference": { "portion_bmid": "string", "measure_unit_name": "string", "gram_weight": "string", "amount": "string" } } ], "ingredient_resolutions": [ { "original_text": "string", "parsed": { "quantity_text": "string", "quantity": 0, "unit": "string", "ingredient_name": "string" }, "converted": { "quantity": 0, "unit": "string", "steps": [ { "from_quantity": 0, "from_unit": "string", "to_quantity": 0, "to_unit": "string", "source": "string", "reasoning": "string" } ] }, "matches": { "query_text": "string", "candidates": [ { "ingredient_id": "string", "ingredient_name": "string" } ], "selected_match": { "ingredient_id": "string", "ingredient_name": "string" }, "match_confidence": 0, "search_strategy_used": "standard" } } ], "updated_at": "string" }, "meta": { "version": "string", "request_id": "string", "timestamp": "string" }, "version_id": "string"}