> 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/carbon.md).

# Carbon

Carbon assessment ingestion for dishes

## Ingest a carbon assessment for a dish

> Stores an externally calculated carbon assessment against the current version of the given dish. The assessment is upserted so re-sends are idempotent, and the row is stamped as import-owned (read-only in the Evo UI). \`dishId\` is the Evo Recipe id and must belong to the authenticated organisation.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Carbon","description":"Carbon assessment ingestion for dishes"}],"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":{"DishId":{"name":"dishId","in":"path","required":true,"description":"The Evo Recipe id of the dish to attach the carbon assessment to.","schema":{"type":"string"}}},"schemas":{"CarbonAssessmentInput":{"type":"object","description":"Carbon assessment payload. When externalStatus is not_assessable the figures and rating are ignored and stored as null.","required":["externalStatus"],"properties":{"externalStatus":{"type":"string","enum":["complete","not_assessable"],"description":"Whether the source system could assess the dish."},"carbonRating":{"type":"string","nullable":true,"enum":["A","B","C","D","E"],"description":"Letter rating for a complete assessment."},"emissionsPerKg":{"type":"number","nullable":true,"description":"kg CO2e per kg of product."},"emissionsPerServing":{"type":"number","nullable":true,"description":"kg CO2e per serving."},"totalEmissions":{"type":"number","nullable":true,"description":"Total kg CO2e for the assessed recipe."},"carMilesEquivalent":{"type":"number","nullable":true,"description":"Equivalent car miles for the total emissions."},"externalStatusReason":{"type":"string","nullable":true,"description":"Empty-state message; only meaningful for not_assessable."},"externalUrl":{"type":"string","nullable":true,"description":"Link to the assessment in the source system."},"labelUrl":{"type":"string","nullable":true,"description":"Link to the generated carbon label image."},"sourceTenantIdentifier":{"type":"string","nullable":true,"description":"Source-system tenant/region identifier (e.g. 'UK')."},"externalId":{"type":"string","nullable":true,"description":"Product/recipe id in the source system."}}},"CarbonAssessmentResult":{"type":"object","required":["success","dishId","recipeVersionId","emissions"],"properties":{"success":{"type":"boolean"},"dishId":{"type":"string"},"recipeVersionId":{"type":"string"},"emissions":{"type":"object","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":"number","nullable":true},"emissionsPerServing":{"type":"number","nullable":true},"totalEmissions":{"type":"number","nullable":true},"carMilesEquivalent":{"type":"number","nullable":true},"externalUrl":{"type":"string","nullable":true},"labelUrl":{"type":"string","nullable":true},"updatedAt":{"type":"string","format":"date-time"}}}}},"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":{"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"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/dishes/{dishId}/carbon":{"post":{"operationId":"IngestDishCarbonAssessment","summary":"Ingest a carbon assessment for a dish","description":"Stores an externally calculated carbon assessment against the current version of the given dish. The assessment is upserted so re-sends are idempotent, and the row is stamped as import-owned (read-only in the Evo UI). `dishId` is the Evo Recipe id and must belong to the authenticated organisation.","tags":["Carbon"],"parameters":[{"$ref":"#/components/parameters/DishId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CarbonAssessmentInput"}}}},"responses":{"200":{"description":"The carbon assessment was stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CarbonAssessmentResult"}}}},"400":{"description":"The request body failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No dish found for the given id in the caller's organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The dish has no current version to attach an assessment to.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"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/carbon.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.
