> For the complete documentation index, see [llms.txt](https://docs.hos.accessacloud.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hos.accessacloud.com/evo-recipes-api/recipes.md).

# Recipes

Recipe catalogue with versioning and tagging

## List recipes

> Returns a projection of recipes for the authenticated organisation. Defaults to published, active recipes ordered by name ascending. Supplying \`updatedSince\` switches the ordering to \`updatedAt\` ascending for incremental sync; keep the filter set stable while paging, because the cursor encoding depends on the ordering.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Recipes","description":"Recipe catalogue with versioning and tagging"}],"servers":[{"url":"https://api.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Production"},{"url":"https://api-dev.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Development"},{"url":"https://api-staging.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Staging"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth2 client credentials JWT obtained from the Access Identity M2M token endpoint (`POST https://api.hos.accessacloud.com/platform/m2m-auth/v1/token`). The token request must use `grant_type=client_credentials` with `audience=fandb-platform-api evo-dishes-recipes` and `scope=fandb.read fandb.write openid <organisationId>`, where `<organisationId>` is the calling organisation's GUID. The response returns `{ \"access_token\": \"<JWT>\", \"expires_in\": 3599, \"scope\": \"fandb.read fandb.write openid <organisationId>\", \"token_type\": \"bearer\" }`. Tokens expire after `expires_in` seconds (typically ~1 hour). APIM validates the token at the gateway. The token's `scp` claim must also carry the caller's organisation ID as a bare GUID; the backend resolves the tenant by matching that GUID case-insensitively against either the `id` or the `workspace_org_id` column. A token with no organisation GUID is rejected with `401`, and one carrying more than one distinct organisation GUID with `403`."}},"parameters":{"PageSize":{"name":"page_size","in":"query","required":false,"description":"Number of items per page. Clamped to the range [1, 500]. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"Opaque cursor for keyset pagination. Pass the next_cursor value from a previous response to fetch the next page.","schema":{"type":"string"}},"ActiveFilter":{"name":"active","in":"query","required":false,"description":"Filter on the active flag. Use `all` to disable the filter. Defaults to `true`.","schema":{"type":"string","enum":["true","false","all"],"default":"true"}},"RecipeStatusFilter":{"name":"status","in":"query","required":false,"description":"Filter on recipe status. Use `all` to disable the filter. Defaults to `PUBLISHED`.","schema":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED","all"],"default":"PUBLISHED"}},"UpdatedSince":{"name":"updatedSince","in":"query","required":false,"description":"ISO 8601 timestamp. Returns only records updated at or after this instant, ordered by `updatedAt` ascending for incremental sync.","schema":{"type":"string","format":"date-time"}}},"schemas":{"PaginatedResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"Pagination":{"type":"object","required":["page_size","has_next_page","next_cursor"],"properties":{"page_size":{"type":"integer","description":"The page size used for this request."},"has_next_page":{"type":"boolean","description":"Whether more results exist beyond this page."},"next_cursor":{"type":"string","nullable":true,"description":"Cursor to pass as the cursor query parameter for the next page. Null when there are no more results."}}},"RecipeListItem":{"type":"object","description":"Recipe list projection. Cost, GP, and margin figures are deliberately excluded from this API.","required":["id","name","status","productType","tags","updatedAt"],"properties":{"id":{"type":"string","description":"Unique recipe identifier (CUID)."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"imageUrl":{"type":"string","nullable":true},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]},"productType":{"type":"string","enum":["FOOD","DRINK"],"description":"NPM scoring product type classification."},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagRef"}},"updatedAt":{"type":"string","format":"date-time"}}},"TagRef":{"type":"object","description":"Lightweight reference to a tag.","required":["id","name","color"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string","description":"Hex colour code."}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code (e.g. INVALID_QUERY_PARAMETER, MISSING_PATH_PARAMETER, RESOURCE_NOT_FOUND, INTERNAL_ERROR)."},"parameter":{"type":"string","description":"The offending query or path parameter, when applicable."}}}},"responses":{"BadRequest":{"description":"A query or path parameter failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid, or expired authorization token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The token does not grant access to exactly one organisation, so no tenant can be resolved from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"OrganizationNotFound":{"description":"No tenant found matching the organisation GUID in the token's `scp` claim.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/recipes":{"get":{"operationId":"GetRecipes","summary":"List recipes","description":"Returns a projection of recipes for the authenticated organisation. Defaults to published, active recipes ordered by name ascending. Supplying `updatedSince` switches the ordering to `updatedAt` ascending for incremental sync; keep the filter set stable while paging, because the cursor encoding depends on the ordering.","tags":["Recipes"],"parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/ActiveFilter"},{"$ref":"#/components/parameters/RecipeStatusFilter"},{"$ref":"#/components/parameters/UpdatedSince"}],"responses":{"200":{"description":"Paginated list of recipes.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RecipeListItem"}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/OrganizationNotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Get a recipe

> Returns the full detail of one recipe from its \*\*current version\*\* only — there is no \`version\` parameter and historic versions are not exposed. Components are capped at 500 and sub-recipes are summarised by reference rather than expanded, so the payload depth is bounded. Allergen and nutrition data are the stored kind only (component ingredient associations, version allergen overrides and the manually entered nutrition row); nothing is calculated and no cost, GP or margin figures are returned.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Recipes","description":"Recipe catalogue with versioning and tagging"}],"servers":[{"url":"https://api.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Production"},{"url":"https://api-dev.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Development"},{"url":"https://api-staging.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Staging"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth2 client credentials JWT obtained from the Access Identity M2M token endpoint (`POST https://api.hos.accessacloud.com/platform/m2m-auth/v1/token`). The token request must use `grant_type=client_credentials` with `audience=fandb-platform-api evo-dishes-recipes` and `scope=fandb.read fandb.write openid <organisationId>`, where `<organisationId>` is the calling organisation's GUID. The response returns `{ \"access_token\": \"<JWT>\", \"expires_in\": 3599, \"scope\": \"fandb.read fandb.write openid <organisationId>\", \"token_type\": \"bearer\" }`. Tokens expire after `expires_in` seconds (typically ~1 hour). APIM validates the token at the gateway. The token's `scp` claim must also carry the caller's organisation ID as a bare GUID; the backend resolves the tenant by matching that GUID case-insensitively against either the `id` or the `workspace_org_id` column. A token with no organisation GUID is rejected with `401`, and one carrying more than one distinct organisation GUID with `403`."}},"parameters":{"RecipeId":{"name":"recipeId","in":"path","required":true,"description":"The recipe id, which must belong to the authenticated organisation.","schema":{"type":"string"}}},"schemas":{"RecipeDetail":{"type":"object","description":"Recipe detail projection built from the current version only. Cost, GP and margin figures are deliberately excluded from this API.","required":["id","name","status","productType","servings","active","isVisible","tags","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"imageUrl":{"type":"string","nullable":true},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]},"productType":{"type":"string","enum":["FOOD","DRINK"]},"servings":{"type":"string","format":"decimal"},"active":{"type":"boolean"},"isVisible":{"type":"boolean"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagRef"}},"currentVersion":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeVersionDetail"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TagRef":{"type":"object","description":"Lightweight reference to a tag.","required":["id","name","color"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string","description":"Hex colour code."}}},"RecipeVersionDetail":{"type":"object","description":"The recipe's current version. Cost, GP and margin are excluded.","required":["id","versionNumber","status","name","servings","components","allergenOverrides","metadata","updatedAt"],"properties":{"id":{"type":"string"},"versionNumber":{"type":"integer"},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]},"name":{"type":"string"},"description":{"type":"string","nullable":true},"instructions":{"type":"string","nullable":true},"servings":{"type":"string","format":"decimal"},"prepTime":{"type":"integer","nullable":true,"description":"Preparation time in minutes."},"cookTime":{"type":"integer","nullable":true,"description":"Cooking time in minutes."},"shelfLifeDays":{"type":"integer","nullable":true},"outputQuantity":{"type":"string","format":"decimal","nullable":true},"outputUnit":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UnitRef"}]},"portionSizeG":{"type":"string","format":"decimal","nullable":true},"cookingLossPercent":{"type":"string","format":"decimal"},"quidDeclarationOverride":{"type":"string","nullable":true},"components":{"type":"array","description":"Capped at 500 components.","items":{"$ref":"#/components/schemas/RecipeComponent"}},"allergenOverrides":{"type":"array","items":{"$ref":"#/components/schemas/AllergenOverride"}},"nutritionOverride":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeNutritionOverride"}]},"dietarySuitability":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/DietarySuitability"}]},"emissions":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeEmissions"}]},"quidLabel":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeQuidLabel"}]},"metadata":{"type":"array","items":{"$ref":"#/components/schemas/RecipeMetadataEntry"}},"updatedAt":{"type":"string","format":"date-time"}}},"UnitRef":{"type":"object","description":"Lightweight reference to a measurement unit.","required":["id","name","abbreviation","unitType"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"abbreviation":{"type":"string"},"unitType":{"type":"string","enum":["WEIGHT","VOLUME","COUNT"]}}},"RecipeComponent":{"type":"object","description":"One component of the recipe's current version. Sub-recipes are summarised by reference — they are never expanded recursively.","required":["id","componentType","sortOrder","quantity","unit"],"properties":{"id":{"type":"string"},"componentType":{"type":"string","enum":["INGREDIENT","SUB_RECIPE"]},"sortOrder":{"type":"integer"},"quantity":{"type":"string","format":"decimal"},"prepMethod":{"type":"string","nullable":true},"cookMethod":{"type":"string","nullable":true},"wastePercentage":{"type":"string","format":"decimal","nullable":true},"unit":{"$ref":"#/components/schemas/UnitRef"},"ingredient":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeComponentIngredient"}]},"subRecipeId":{"type":"string","nullable":true},"subRecipeVersionId":{"type":"string","nullable":true},"subRecipe":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeRef"}]}}},"RecipeComponentIngredient":{"type":"object","required":["id","name","allergens"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"productCode":{"type":"string","nullable":true},"ingredientDeclaration":{"type":"string","nullable":true},"allergens":{"type":"array","items":{"$ref":"#/components/schemas/AllergenAssociation"}}}},"AllergenAssociation":{"description":"Allergen as stored against an ingredient or supplier offer. `status` is the recorded association, never a calculated roll-up.","allOf":[{"$ref":"#/components/schemas/AllergenRef"},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["NO","YES","MAY_CONTAIN"]}}}]},"AllergenRef":{"type":"object","description":"Lightweight allergen reference as included on a product.","required":["id","code","name","severity"],"properties":{"id":{"type":"string"},"code":{"type":"string","description":"Unique allergen code (e.g. CELERY, EGGS, MILK)."},"name":{"type":"string"},"severity":{"type":"string","enum":["MILD","MODERATE","SEVERE","LIFE_THREATENING"]}}},"RecipeRef":{"type":"object","description":"Lightweight reference to a recipe.","required":["id","name","status"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]}}},"AllergenOverride":{"description":"Cross-contamination allergen override stored against a recipe version.","allOf":[{"$ref":"#/components/schemas/AllergenRef"},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["NO","YES","MAY_CONTAIN"]},"reason":{"type":"string","nullable":true}}}]},"RecipeNutritionOverride":{"description":"Manually entered nutrition for a recipe version.","allOf":[{"$ref":"#/components/schemas/NutritionValues"},{"type":"object","required":["inputBasis","updatedAt"],"properties":{"inputBasis":{"type":"string","enum":["PER_100G","PER_PORTION","PER_RECIPE"]},"updatedAt":{"type":"string","format":"date-time"}}}]},"NutritionValues":{"type":"object","description":"Big-8 plus extended nutrition values. Decimal columns are serialised as strings to preserve precision.","properties":{"energyKcal":{"type":"string","format":"decimal","nullable":true},"energyKj":{"type":"string","format":"decimal","nullable":true},"fatG":{"type":"string","format":"decimal","nullable":true},"saturatedFatG":{"type":"string","format":"decimal","nullable":true},"carbohydrateG":{"type":"string","format":"decimal","nullable":true},"sugarsG":{"type":"string","format":"decimal","nullable":true},"proteinG":{"type":"string","format":"decimal","nullable":true},"saltG":{"type":"string","format":"decimal","nullable":true},"fibreG":{"type":"string","format":"decimal","nullable":true},"monoUnsaturatesG":{"type":"string","format":"decimal","nullable":true},"polyUnsaturatesG":{"type":"string","format":"decimal","nullable":true},"transFatG":{"type":"string","format":"decimal","nullable":true},"sodiumMg":{"type":"string","format":"decimal","nullable":true},"freeSugarsG":{"type":"string","format":"decimal","nullable":true}}},"DietarySuitability":{"type":"object","description":"Stored dietary-suitability flags. Nulls mean \"not declared\".","properties":{"isVegetarian":{"type":"boolean","nullable":true},"isVegan":{"type":"boolean","nullable":true},"isDairyFree":{"type":"boolean","nullable":true},"isGlutenFree":{"type":"boolean","nullable":true},"isLactoseFree":{"type":"boolean","nullable":true},"isNutFree":{"type":"boolean","nullable":true},"isHalalSuitable":{"type":"boolean","nullable":true},"isKosherSuitable":{"type":"boolean","nullable":true},"isHinduismSuitable":{"type":"boolean","nullable":true}}},"RecipeEmissions":{"type":"object","description":"Stored carbon assessment for the current version.","required":["assessmentStatus"],"properties":{"assessmentStatus":{"type":"string","enum":["COMPLETE","NOT_ASSESSABLE"]},"statusReason":{"type":"string","nullable":true},"carbonRating":{"type":"string","nullable":true,"enum":["A","B","C","D","E"]},"emissionsPerKg":{"type":"string","format":"decimal","nullable":true},"emissionsPerServing":{"type":"string","format":"decimal","nullable":true},"totalEmissions":{"type":"string","format":"decimal","nullable":true},"carMilesEquivalent":{"type":"string","format":"decimal","nullable":true},"externalUrl":{"type":"string","nullable":true},"labelUrl":{"type":"string","nullable":true},"updatedAt":{"type":"string","format":"date-time"}}},"RecipeQuidLabel":{"type":"object","description":"Cached QUID label generated for the current version.","required":["generatedLabel","totalWeightGrams","hasWarnings","generatedAt"],"properties":{"generatedLabel":{"description":"Generated label document (JSON)."},"totalWeightGrams":{"type":"string","format":"decimal"},"hasWarnings":{"type":"boolean"},"warningMessages":{"description":"Warning messages raised while generating the label (JSON)."},"generatedAt":{"type":"string","format":"date-time"}}},"RecipeMetadataEntry":{"type":"object","required":["key","header","sortOrder","content"],"properties":{"key":{"type":"string"},"header":{"type":"string"},"sortOrder":{"type":"integer"},"content":{"type":"string"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code (e.g. INVALID_QUERY_PARAMETER, MISSING_PATH_PARAMETER, RESOURCE_NOT_FOUND, INTERNAL_ERROR)."},"parameter":{"type":"string","description":"The offending query or path parameter, when applicable."}}}},"responses":{"BadRequest":{"description":"A query or path parameter failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid, or expired authorization token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The token does not grant access to exactly one organisation, so no tenant can be resolved from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No resource found for the given id in the caller's organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/recipes/{recipeId}":{"get":{"operationId":"GetRecipe","summary":"Get a recipe","description":"Returns the full detail of one recipe from its **current version** only — there is no `version` parameter and historic versions are not exposed. Components are capped at 500 and sub-recipes are summarised by reference rather than expanded, so the payload depth is bounded. Allergen and nutrition data are the stored kind only (component ingredient associations, version allergen overrides and the manually entered nutrition row); nothing is calculated and no cost, GP or margin figures are returned.","tags":["Recipes"],"parameters":[{"$ref":"#/components/parameters/RecipeId"}],"responses":{"200":{"description":"The recipe and its current version.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeDetail"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hos.accessacloud.com/evo-recipes-api/recipes.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
