BetterMenu
Build FDA labels from recipes
- Category
- Operations
- Primary Subcategory
- Ecommerce Operations Platforms
Integration details
Description
BetterMenu keeps recipe formulation, nutrition analysis and FDA labeling in one versioned system, so compliance stops being a separate project at the end of development. Search standard and branded ingredients, resolve kitchen measures to gram weights, and calculate per-serving and per-container nutrition against the FDA reference values in 21 CFR 101. Add custom ingredients with your own nutrition data, set serving sizes, and export the Nutrition Facts label. Every recipe is versioned: reformulate freely, then see which ingredient change moved which nutrient, and which version any given label came from. Values carry their source, so you can answer where a number came from without reconstructing it. For food manufacturers, co-packers, and R&D and regulatory teams working on packaged food sold in the United States.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Ecommerce Operations Platforms
- Secondary Subcategories
- None listed
- Brand
- BetterMenu
- Access
- Account required
- First tracked
- 2026-09-13
- Tool count
- 58
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Ecommerce Operations Platforms
View Category58 tools agents can invoke
Add a serving to a recipe — set serving size. Creates a new serving entry. Does not replace existing servings — use updateRecipeServing to modify an existing serving by ID. Accepts serving size input (user_provided or racc_guided), stores the raw input, and resolves the serving_size when recipe nutrition is already present. Per-serving nutrition facts for the new serving are computed and folded into the same Version — always, with no way to opt out. No follow-up call is needed. For racc_guided mode, use searchUsRaccCategories to find the right RACC food category first.
addRecipeServing
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Archive a custom ingredient — withdraw it from active use. Soft: never a hard delete, the entity stays readable and pinned references in existing recipes are undisturbed. An archived ingredient is rejected from NEW recipe composition; use `unarchiveCustomIngredient` to reverse. Idempotent: re-archiving an already-archived ingredient returns the existing `version_id`.
archiveCustomIngredient
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Archive a recipe — take it offline. Sets the lifecycle marker to ARCHIVED and writes a new Version. Use ``unarchiveRecipe`` to reverse. Idempotent: re-archiving an already-archived recipe returns the existing ``version_id``.
archiveRecipe
Compute gram weights for ingredient items — convert quantities to grams using portion data and standard measurement tables. Deterministic only. ② of 6 | Next: ④ setRecipeIngredients Stateless — no recipe needed yet. Use this to answer: "how many grams is 2 cups of flour?", "convert 3 eggs to grams", "get gram weight for these ingredients". ① searchIngredients returns matches with no gram-weight detail — always follow with this step. Accepts a batch of (ingredient_id, quantity, unit) items and returns gram weights. For a branded product (getIngredient source="product"), unit string matching never applies — its portion has no unit name, only a label like "1 tsp (5g)". Pass that portion's id (getIngredient's portions[].id) as portion_id instead of unit to resolve it directly. When an item has no deterministic portion match, its status is "needs_resolution": ask the user for the gram weight directly and pass it as quantity_grams to ④ setRecipeIngredients. Do not estimate gram weights yourself.
computeConversions
Promote a draft custom ingredient to active; only active ingredients can be composed into recipes. A draft ingredient is always rejected from recipe composition. Confirming an already-active or archived ingredient is rejected — this is a one-time transition, not idempotent.
confirmCustomIngredient
Create a new custom ingredient as an empty draft. Only `name` is required. The response carries `version_id` — the sealed Version ULID — which callers can pass back on a future mutation for optimistic concurrency.
createCustomIngredient
Create a new recipe in ACTIVE state. Only name is required. Country defaults to US. Demographic defaults to adults_and_children_over_4. Recipes beyond your plan's included monthly allowance are billed at your plan's metered rate. Manage your plan and usage in BetterMenu Studio.
createRecipe
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Permanently delete a custom ingredient — irreversible via the API. `restoreCustomIngredient` is refused on a `deleted` ingredient (409 `custom_ingredient_not_restorable`), so no prior version can undo this. Scoped to `draft`, never-confirmed ingredients with zero recipe usage only: a typo'd or misnamed draft that was never confirmed and never composed into a recipe. Rejected once the ingredient has been confirmed (`active`), `archived`, or is already `deleted` — use `archiveCustomIngredient` to withdraw an ingredient that's ever been active. Rejected if any recipe pins this ingredient, even though a `draft` cannot normally acquire usage — check `getCustomIngredientUsage` first if unsure. Unlike `deleteRecipe`, the ingredient remains readable afterward with `status=deleted` — the record and every version before the delete are retained; what ends is any further use of the ingredient.
deleteCustomIngredient
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Delete a recipe (permanent — irreversible via the API). Once deleted, the recipe is fully hidden from all endpoints: it no longer appears in list or detail reads, version history is inaccessible, and ``restoreRecipe`` also returns 404. There is no un-delete — ``restoreRecipe`` is a version rollback for live recipes, not a recovery mechanism for deleted ones. Re-deleting an already-deleted recipe returns 404 (``recipe_not_found``), which clients should treat as a successful deletion since the recipe is already gone.
deleteRecipe
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Delete the recipe's label configuration. Returns 204 No Content on success; 404 when no active configuration exists. Sends ``If-Match: W/"<version_id>"`` to guard against concurrent writes — returns 412 on conflict. Available only on API versions declaring the ``recipe_versioning`` capability.
deleteRecipeLabelConfiguration
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Delete a serving by ID. The serving is excluded from listRecipeServings but is retained for audit compliance. Returns 204 No Content on success. On versions declaring the `recipe_versioning` capability, the response carries an `ETag` header set to the new Version ULID so clients can pass it back as `If-Match` on the next mutation — 204 has no body to carry the field.
deleteRecipeServing
Generate (or return cached) label artifact(s) for one serving. On the first request for a given (recipe version, serving, format, resolution) combination the label HTML is assembled, rendered by the label-renderer Lambda, and the result is permanently cached in S3. Subsequent requests return the cached artifact without re-rendering. Concurrent first-download requests are safe — only one PUT lands; all others receive a pre-signed URL for the same artifact. Organizations in their trial period always receive a DRAFT-watermarked artifact, regardless of the ``draft_watermark`` parameter — as do organizations whose billing status cannot currently be confirmed. Otherwise the watermark is controlled via that parameter. Organizations on a non-subscription plan (``past_due``/``expired``/ ``cancelled``) may still re-fetch an already-cached artifact, but a request that would require a fresh render (bm-be#2296) is denied with a 402. Available only on API versions declaring the ``recipe_versioning`` capability.
exportRecipeLabelArtifact
Fetch a custom ingredient by id.
getCustomIngredient
Return the compliance timeline for a custom ingredient. Lists typed audit events newest-first — actor, channel, timestamp, and the fields set/changed.
getCustomIngredientAuditTrail
List the organization's recipes that pin this custom ingredient. Backed by an eventually-consistent, near-real-time reverse index. `version_id` is applied as a DynamoDB filter after the page is read, so a filtered page can return fewer than `limit` items — possibly zero — even when more matches exist further in. An empty page with `meta.has_more: true` is not an empty result set: keep paging with `meta.cursor` until `meta.has_more` is false. Unfiltered pages are unaffected.
getCustomIngredientUsage
Fetch the custom ingredient exactly as it existed at `version_id`. Returns the same full-entity envelope as `getCustomIngredient`, reconstructed from the immutable content-addressed history instead of the live HEAD — the entity's "time travel" counterpart to `restoreCustomIngredient`. `data` reflects the historical snapshot; `version_id` echoes the requested version. Returns 404 when the custom ingredient does not exist, or when `version_id` does not exist in its history.
getCustomIngredientVersion
Return a structural diff of `version_id` relative to `compared_to` (defaults to its parent). `before` holds values at the comparison point; `after` holds values at the subject version. Only changed top-level fields appear in `data.field_changes`; an empty map means the two states are equivalent. Each changed field also carries a `data.field_relevance` entry classifying its downstream label impact (ADR 0008 D7): `label_affecting`, `availability_affecting`, or `non_label_affecting`. Diffing a version against itself returns 400.
getCustomIngredientVersionChanges
Read the calling organization's subscription plan, trial state, pending cancellation, feature gates, and per-quota usage. quotas[key].limit reflects the effective limit (trial_limit when is_trialing is true). metered_usage_enabled reports whether the organization accepts charges beyond its included monthly allowance.
getEntitlementStatus
Resolve one ingredient by id — a custom ingredient (`cing_…` — the caller organization's own) or a standard reference ingredient, whichever the id belongs to.
getIngredient
List the organization's recipes that pin `ingredient_id` — standard or custom. Backed by an eventually-consistent, near-real-time reverse index; not a hard read-your-writes guarantee immediately after a recipe save. `version_id` is applied as a DynamoDB filter after the page is read, so a filtered page can return fewer than `limit` items — possibly zero — even when more matches exist further in. An empty page with `meta.has_more: true` is not an empty result set: keep paging with `meta.cursor` until `meta.has_more` is false. Unfiltered pages are unaffected.
getIngredientUsage
Returns the most recent ingredient resolution for this recipe. Only reflects the server-side resolve → confirm workflow (startIngredientResolution → confirmIngredients). Returns 404 when no resolution session exists — this is correct and expected when ingredients were set via setRecipeIngredients, which bypasses the resolution pipeline entirely. To read current ingredients regardless of how they were set, use getRecipeIngredients.
getLatestIngredientResolution
Return per-nutrient ingredient breakdown for the recipe. Shows which ingredients contribute the most to each nutrient (protein, fat, calories, vitamins, minerals, etc.) with percentage contributions. Use ``nutrient_set`` to filter to a predefined group and ``top_n`` to limit contributors per nutrient. Pass ``?version_id=`` to read analysis at a historical snapshot. Returns 404 if nutrition has not been computed yet.
getRecipeNutritionalAnalysis
Get per-container nutrition facts, optionally pinned to a historical version. Returns compliant-rounded nutrient values for the full container. Accepts ``?version_id=`` to read facts at a specific version snapshot. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404.
getRecipePerContainerNutritionFacts
Get per-serving nutrition facts, optionally pinned to a historical version. Returns compliant-rounded nutrient values and percent daily values for one serving. Accepts ``?version_id=`` to read facts at a specific version snapshot. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404.
getRecipePerServingNutritionFacts
Get a recipe by id, optionally pinned to a historical version. `?version_id=` (omit ⇒ latest) selects the snapshot. The response body's top-level `version_id` mirrors the resolved snapshot — HEAD when omitted, the supplied version otherwise — and the `ETag: W/"{version_id}"` response header is derived from that field. Clients can pass the ETag back as `If-Match` on the next mutation for optimistic concurrency. The response body's `data.status` (`active` / `archived` / `deleted`) is the recipe lifecycle state. Available only on API versions declaring the `recipe_versioning` capability. Requests without this capability receive a 404.
getRecipe
Return the compliance timeline for a recipe. Lists typed audit events newest-first. Each event carries the actor, channel, timestamp, changed fields, before/after payload, rationale, and a tamper-evidence ``record_hash``. Use this endpoint to answer: "who changed what and why?", "what was the ingredient list before the last edit?", "show me all nutrition recomputations since version V". For the tamper-evident chain of state snapshots use ``listRecipeVersions`` instead. Pagination: pass `meta.cursor` from the previous response back as `cursor` on the next request, and keep paging until `meta.has_more` is false. `actor_id`, `actor_type`, `since_version_id` and `up_to_version_id` are applied as DynamoDB filters after the page is read, so a filtered page can return fewer than `limit` events — possibly zero — even when more matches exist further in. An empty page with `meta.has_more: true` is not an empty result set: keep paging with `meta.cursor` rather than reading a short or empty page as the end of the timeline. `event_type` and the `from`/`to` range narrow the index range itself and are unaffected. Passing `event_type` selects a different index that has no cursor: that path returns a single page of at most `limit` events and always reports `meta.has_more: false`, which therefore does not mean the timeline is exhausted. Narrow with `from`/`to`, or raise `limit`, to see more of a typed slice.
getRecipeAuditTrail
Get all ingredients in a recipe in order with their resolved names, quantities, and positions. The top-level ``version_id`` mirrors the recipe's HEAD ULID on the ``main`` branch — clients can pass it back as ``If-Match`` on the next mutation for optimistic concurrency. Accepts ``?version_id=`` to read ingredients at a specific historical version snapshot. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404. Related endpoints: - setRecipeIngredients — save pre-resolved ingredients directly
getRecipeIngredients
Get fully resolved label configuration, optionally pinned to a historical version. Accepts ``?version_id=`` to read configuration at a specific version snapshot. Returns 404 when ``version_id`` is supplied but no matching version exists. Returns 500 when the stored version uses a data format that this API version cannot read. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404.
getRecipeLabelConfiguration
Return total recipe nutrition (batch-level, all ingredients summed) — not per-serving. ``reference_weight_grams`` is the total weight of all ingredients combined; no per-serving amounts or %DV are included. Pass ``?version_id=`` to read nutrition at a historical snapshot. Returns 404 if nutrition has not been computed yet; use computeRecipeNutrition to trigger a manual recompute.
getRecipeNutrition
Get a render-ready nutrition label for one serving, optionally pinned to a version. Assembles header, regulatory-ordered nutrient columns (per-serving and optional per-container), footnotes, staleness, and completeness into a single response ready for label rendering. Accepts ``?version_id=`` to read the label at a specific version snapshot. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404.
getRecipeNutritionLabel
Return a structural diff of ``version_id`` relative to ``compared_to`` (defaults to its parent). ``before`` holds values at the comparison point; ``after`` holds values at the subject version. Only changed top-level fields appear in ``data.field_changes``; an empty map means the two states are equivalent. For rollback preview, pass ``compared_to={current_head}`` to see what reverting to ``version_id`` would change. Diffing a version against itself returns 400.
getRecipeVersionChanges
Serving nutrition facts analysis with ingredient contributions and rounding audit trail. Returns ingredient contributions (scaled to this serving's weight) alongside full ValueRoundingOutcome and DVRoundingOutcome for each nutrient. Supports filtering by ``nutrient_set`` and/or comma-separated BMIDs. Accepts ``?version_id=`` to read analysis at a specific version snapshot. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404.
getRecipeServingNutritionFactsAnalysis
Get a single serving by id, optionally pinned to a historical version. `?version_id=` (omit ⇒ latest) selects the snapshot. The response body's top-level `version_id` mirrors the resolved snapshot — HEAD when omitted, the supplied version otherwise — and the `ETag: W/"{version_id}"` response header is derived from that field. Clients can pass the ETag back as `If-Match` on the next mutation for optimistic concurrency. Returns the serving size (household measure, metric, servings per container), dual-column label status, and flags indicating whether per-serving and per-container nutrition facts have been computed. Available only on API versions declaring the `recipe_versioning` capability. Requests without this capability receive a 404.
getRecipeServing
Get the FDA daily value for a specific nutrient — recommended daily intake for one nutrient, %DV reference amount. Use this to answer: "what's the daily value for protein?", "how much calcium should I get per day?", "recommended vitamin D intake" Returns the FDA daily value reference for a specific nutrient BMID (BetterMenu nutrient identifier, e.g., n_protein, n_vitamin_c) and demographic (target population) combination per 21 CFR § 101.9. The demographic parameter is REQUIRED — daily values vary by population group. Cache-Control: 24 hours — these are regulatory constants. Related endpoints: - listUsFdaDailyValueReferences — see all daily values at once
getUsFdaDailyValueReference
Get details for a specific FDA serving size category — reference amount, label statements, and CFR reference. Use this to answer: "what's the serving size for cookies?", "show details for this serving size category", "what's the reference amount for bread?" Helper for ⑤ addRecipeServing (racc_guided mode). Returns detailed serving size data (RACC — Reference Amounts Customarily Consumed) from 21 CFR § 101.12 including the reference amount in grams, label statements, and target audience. Related endpoints: - searchUsRaccCategories — find a category by name - listUsRaccCategories — browse all categories
getUsRaccCategory
List a custom ingredient's version history, newest first (cursor-paginated, max 50 per page). Each entry includes `version_id`, `parent_version_id`, `created_at`, `created_by`, and an auto-generated `summary` of what changed. For actor/event audit narrative, use `GET /custom-ingredients/{custom_ingredient_id}/audit-trail` instead.
listCustomIngredientVersions
List the organization's custom ingredients — one lightweight summary per row. Filter by `status` to narrow to a single lifecycle state. `status` is applied as a DynamoDB filter after the page is read, so a filtered page can return fewer than `limit` items — possibly zero — even when more matches exist further in. An empty page with `meta.has_more: true` is not an empty result set: keep paging with `meta.cursor` until `meta.has_more` is false. Deleted custom ingredients are included in every page here, filtered or not, because a deleted custom ingredient stays readable. This is the opposite default to `listRecipes`, which excludes deleted recipes from every page regardless of filter. Pass `status=deleted` to list only them.
listCustomIngredients
Returns all server-side ingredient resolution sessions for this recipe, newest first. Each resolution includes the full row data with search candidates and conversion steps. Only reflects the server-side resolve → confirm workflow (startIngredientResolution → confirmIngredients). Returns an empty list when no resolution sessions exist — this is correct and expected when ingredients were set via setRecipeIngredients, which bypasses the resolution pipeline entirely.
listIngredientResolutions
List all active servings for a recipe. Returns every serving defined on the recipe with its computed size, dual-column label status, and nutrition-facts availability flags. The top-level ``version_id`` mirrors the recipe's HEAD ULID on the ``main`` branch — clients can pass it back as ``If-Match`` on the next mutation for optimistic concurrency, or use it to pin a follow-up ``getRecipeServing`` call to the same snapshot. Accepts ``?version_id=`` to read the servings list at a historical version. Available only on API versions declaring the ``recipe_versioning`` capability. Requests without this capability receive a 404.
listRecipeServings
List a recipe's version history, newest first (cursor-paginated, max 50 per page). Each entry includes ``version_id``, ``parent_version_id``, ``created_at``, ``created_by``, and an auto-generated ``summary`` of what changed. Pass ``?at=<iso8601>`` with an explicit UTC offset to resolve the single version active at that timestamp; ``after`` and ``limit`` are ignored in that mode, and 404 is returned when no version exists at or before the given time. For actor/event audit narrative, use ``GET /recipes/{recipe_id}/audit-trail`` instead.
listRecipeVersions
List recipes the caller can access in their organization. Each list item carries `latest_version_id` — the HEAD ULID for the recipe on the `main` branch — so callers can pin follow-up reads or diff against a known commit without a per-row round-trip. Each item also carries `status` — the recipe lifecycle state, here always `active` or `archived`, never `deleted`: a deleted recipe never appears in a list response (see below). Pagination is cursor-based: omit `cursor` on the first page, then pass `meta.cursor` from each response back as `cursor` on the next call. The cursor is self-contained — it carries forward the `sort_by`/`order`/`status` it was issued under, so subsequent pages don't need to resend them. Passing a param that conflicts with what the cursor was issued under starts a fresh query at page 1 under the new param rather than erroring. `meta` echoes the effective `sort_by`/`order`/`status` actually applied. Server caps `limit` at 100. Sort defaults to `updated_at desc` (most recently updated first). `status` filters to `active` or `archived`, and selects a pre-built view partition rather than filtering rows after the read — so a filtered page here fills to `limit` whenever more matches exist. Deleted recipes are excluded from every page regardless of filter, and `deleted` is not an accepted `status` value: a deleted recipe is no longer readable. This is the opposite default to `listCustomIngredients`, which includes deleted custom ingredients in every page because those stay readable. Available only on API versions declaring the `recipe_versioning` capability. Requests without this capability receive a 404.
listRecipes
List FDA daily value references — recommended daily intake, %DV reference amounts, RDI and DRV values for nutrients. Use this to answer: "what are the daily values?", "recommended daily intake for adults", "how much vitamin C per day?", "FDA nutrient reference amounts" Returns all FDA daily value references for the specified demographic (target population, e.g., adults and children 4+) per 21 CFR § 101.9. The demographic parameter is REQUIRED — daily values vary significantly across population groups. Nutrients without established DVs (e.g., Trans Fat, Total Sugars) are included with daily_value=null. Cache-Control: 24 hours — these are regulatory constants. Related endpoints: - getUsFdaDailyValueReference — look up a single nutrient's daily value
listUsFdaDailyValueReferences
List FDA serving size categories — the reference amount people typically eat of a food in one sitting (RACC, Reference Amounts Customarily Consumed, per 21 CFR § 101.12). Helper for ⑤ addRecipeServing (racc_guided mode). Use this to answer: "what serving size categories are available?", "list FDA serving size categories", "find the serving size category for my product", "what serving size category is bread?" Optionally filter by target audience (general or infant/toddler). Related endpoints: - searchUsRaccCategories — search by name instead of browsing - getUsRaccCategory — get details for a specific category
listUsRaccCategories
List the ingredients the caller's organization has actually used, ranked by usage count, recency, or name — spanning standard and custom ingredients in one ordered result set. Distinct from `searchIngredients`: that endpoint answers 'what can I pick from' (the full catalog, relevance-ranked); this one answers 'what does my organization actually use' (usage-ranked, org-scoped only). Pagination is cursor-based, matching `listRecipes`: omit `cursor` on the first page, then pass `meta.next_cursor`/`meta.prev_cursor` back verbatim. `source`/`status` are applied as DynamoDB filters after the page is read, so a filtered page can return fewer than `limit` items — possibly zero — even when more matches exist further in. Keep paging until `meta.has_more` is false rather than reading a short or empty page as the end of the results. **Eventually consistent.** Unlike `listRecipes`, whose rows are written as part of the recipe commit itself, this listing is a background projection: after a recipe is created, edited or deleted, this endpoint can take from seconds to minutes to reflect the change in `used_in_recipes`, `updated_at`, and which ingredients appear at all. A read immediately after a write may legitimately return the previous state — retry rather than treating it as missing data. `getRecipe` and `getIngredientUsage` are read-your-writes consistent and are the right call when you need the effect of a specific commit confirmed.
listUsedIngredients
Partially update a custom ingredient's metadata. Send only the fields you want to change; omitted fields stay unchanged. Wires `name` — rename the ingredient — and `approved_markets`, a full-list replace of the markets this ingredient participates in, which controls whether it appears in `searchIngredients` / the browser typeahead for a given market. Allowed while the ingredient is `draft` or `active`; rejected once `archived`.
patchCustomIngredientMetadata
Partially update recipe metadata — rename, change country, or change demographic. Send only the fields you want to change; omitted fields stay unchanged. **Side effect:** Changing `country` or `demographic` triggers automatic nutrition recomputation. The updated nutrition figures are available immediately after the update completes. The new name must be unique within the organization. All changes are logged in the audit trail. The response carries `version_id` — the sealed Version ULID — which callers pass back as `If-Match` on the next mutation for optimistic concurrency. A mismatch returns 412 with the current `version_id` so the client can refetch and retry.
patchRecipeMetadata
**IMPORTANT: You MUST ask the user for explicit confirmation before calling this tool. Describe what will happen and wait for the user to approve.** Roll back a custom ingredient to the content state it had at a prior version. This is a **full point-in-time restore** — the entity's entire state (nutrients, serving/gram basis, name, lifecycle status, attributes) snaps back to exactly what was recorded in `target_version_id`. This matches the semantics of `git checkout <tag>`: the whole entity reverts, not just the fields that changed between the target and the current HEAD. Lifecycle status is part of that state, so a restore re-projects the target version's status onto HEAD: restoring past an `archive` puts the ingredient back in `active` or `draft`, exactly as `unarchiveCustomIngredient` would. It does **not** undo a delete. A `deleted` ingredient is refused with 409 `custom_ingredient_not_restorable` — `deleteCustomIngredient` is permanent (ADR 0008 D11), and this is what makes it so. `restoreRecipe` refuses a deleted recipe too, by a different route: a deleted recipe is hidden from all reads, so it 404s. Creates a new commit whose content matches `target_version_id`; the existing history is never rewritten. The new `version_id` is returned in the response body — pass it as `If-Match` on subsequent mutations. Returns 404 if the custom ingredient or the target version does not exist; 409 on a `deleted` ingredient or an `If-Match` mismatch. A recipe pinned to a specific custom-ingredient `version_id` is unaffected by this call — pins are immutable by `version_id` (ADR 0007 D2), so restoring the custom ingredient to a different version never changes what an already-pinned recipe reads or computes.
restoreCustomIngredient
Roll back a recipe to the exact state it had at a prior version. WARNING — full point-in-time restore: ALL sub-entities (ingredients, servings, nutrition, label configuration, summary, metadata) revert to exactly what was recorded at target_version_id. Sub-entities added or modified after that version — including servings added later — are removed in the restored commit. This is equivalent to git checkout <tag>: the entire tree reverts, not just the fields that changed. Before calling: use listRecipeVersions to identify the right target_version_id and confirm that version already contains the ingredients, servings, and other sub-entities you want — anything not present there will be gone after restore. Creates a new commit (history is never rewritten). Returns the restored recipe state with a new version_id; pass it as If-Match on subsequent mutations.
restoreRecipe
Runs an ingredient search on the server and returns matching ingredients — the caller organization's custom ingredients AND the requested market's standard reference ingredients, in one list where every custom-ingredient match ranks above every standard match. Pass `q: "*"` to browse (match everything visible for the market) instead of running a text search. Pass `queries` instead of `q` to search multiple terms in one call — each is ranked independently and results are returned as `result_groups`, one per input query.
searchIngredients
Runs a recipe search on the server and returns matching recipes. Pass `q: "*"` to browse (match all recipes the caller can access) instead of running a text search. Every search is restricted to recipes the caller collaborates on.
searchRecipes
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are BetterMenu alternatives on ChatGPT?
As of 2026-09-13, BetterMenu competes with Shopify, base.com, GadgetOS, Juicy Profit Analytics, Lusca, Mergado, Nas.com, Neges, NivaDesk, Nuvemshop, Redo, Replo, Salesfire, Sellergoo, soeru, SyncMe, TiendaNube, Tolstoy, TrueProfit, Dukkani in ChatGPT Ecommerce Operations Platforms, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.