Custom Foods reference
Create, update and delete the user's own foods, with macros per 100 g or 100 ml.
The DailyGoal API is not available on the Free plan. It works with a paid plan or during a free trial. See plans.
Usage notes
Free app accounts can create up to 5 custom foods. Pro has no plan cap. The API itself requires Pro or a trial.
All operations require Pro or a trial. GET and DELETE take query parameters; other methods take a JSON body. The input table also includes any MCP-only idempotency_key argument; REST sends it as a header. See retrying creates. Example ids are synthetic; find your own with the search and list operations.
Operations
save_custom_food: Save custom fooddelete_custom_food: Delete custom food
save_custom_food
POST https://api.dailygoal.fit/v1/custom-foods
MCP tool save_custom_food · Changes data · Destructive · DailyGoal data only · Accepts Idempotency-Key
Create a custom food, or update one by passing its id. Replaces every field, with macros in grams per 100 g (or 100 ml) and one serving's size. Use it for foods search_foods cannot find. It records nothing eaten: call log_food_entry with the returned id to log the food.
Input
| Field | Type | Description |
|---|---|---|
| idoptional | string | The custom food to update, from a previous save_custom_food or search_foods. Omit it to create a new custom food. |
| name | string | Food name, for example 'Greek yoghurt 2%'. |
| brandNameoptional | string | Brand, if any. Blank or omitted means no brand. |
| protein | number | Protein in grams per 100 g, or per 100 ml when servingSizeUnit is ml. |
| carbs | number | Carbohydrate in grams per 100 g or 100 ml. |
| fat | number | Fat in grams per 100 g or 100 ml. |
| alcoholoptional | number | Alcohol in grams per 100 g or 100 ml. Defaults to 0. |
| servingSize | number | Size of one serving, in servingSizeUnit, for example 150. |
| servingSizeUnit | "g" | "ml" | Unit of servingSize and of the per-100 macro values. |
| servingSizeTextoptional | string | Label for one serving, for example '1 pot'. Blank or omitted means '1 serving'. |
| idempotency_keyoptional | string | Optional. A unique value for this create, for example a UUID. Retrying with the same key and arguments within 24 hours returns the first result instead of creating a duplicate. |
Full input schema, including bounds and nested alternatives (MCP)
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The custom food to update, from a previous save_custom_food or search_foods. Omit it to create a new custom food."
},
"name": {
"type": "string",
"pattern": "\\S",
"description": "Food name, for example 'Greek yoghurt 2%'."
},
"brandName": {
"type": "string",
"description": "Brand, if any. Blank or omitted means no brand."
},
"protein": {
"type": "number",
"minimum": 0,
"description": "Protein in grams per 100 g, or per 100 ml when servingSizeUnit is ml."
},
"carbs": {
"type": "number",
"minimum": 0,
"description": "Carbohydrate in grams per 100 g or 100 ml."
},
"fat": {
"type": "number",
"minimum": 0,
"description": "Fat in grams per 100 g or 100 ml."
},
"alcohol": {
"type": "number",
"minimum": 0,
"description": "Alcohol in grams per 100 g or 100 ml. Defaults to 0."
},
"servingSize": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Size of one serving, in servingSizeUnit, for example 150."
},
"servingSizeUnit": {
"type": "string",
"enum": [
"g",
"ml"
],
"description": "Unit of servingSize and of the per-100 macro values."
},
"servingSizeText": {
"type": "string",
"description": "Label for one serving, for example '1 pot'. Blank or omitted means '1 serving'."
},
"idempotency_key": {
"type": "string",
"maxLength": 255,
"description": "Optional. A unique value for this create, for example a UUID. Retrying with the same key and arguments within 24 hours returns the first result instead of creating a duplicate."
}
},
"required": [
"name",
"protein",
"carbs",
"fat",
"servingSize",
"servingSizeUnit"
],
"additionalProperties": true
}Output
| Field | Type | Description |
|---|---|---|
| created | boolean | True when this call created the custom food, false when it updated one. |
| customFood | object | |
| customFood.id | string | Custom food id. Pass it to log_food_entry as the custom food id. |
| customFood.name | string | |
| customFood.brandNameoptional | string | |
| customFood.protein | number | Grams per 100 g or 100 ml. |
| customFood.carbs | number | Grams per 100 g or 100 ml. |
| customFood.fat | number | Grams per 100 g or 100 ml. |
| customFood.alcohol | number | Grams per 100 g or 100 ml. |
| customFood.calories | number | Kilocalories per 100 g or 100 ml, calculated from the macros. |
| customFood.servingSize | number | |
| customFood.servingSizeUnit | string | g or ml. Foods created by the in-app assistant can also use count units such as item. |
| customFood.servingSizeText | string |
Full output schema
{
"type": "object",
"properties": {
"created": {
"type": "boolean",
"description": "True when this call created the custom food, false when it updated one."
},
"customFood": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Custom food id. Pass it to log_food_entry as the custom food id."
},
"name": {
"type": "string"
},
"brandName": {
"type": "string"
},
"protein": {
"type": "number",
"description": "Grams per 100 g or 100 ml."
},
"carbs": {
"type": "number",
"description": "Grams per 100 g or 100 ml."
},
"fat": {
"type": "number",
"description": "Grams per 100 g or 100 ml."
},
"alcohol": {
"type": "number",
"description": "Grams per 100 g or 100 ml."
},
"calories": {
"type": "number",
"description": "Kilocalories per 100 g or 100 ml, calculated from the macros."
},
"servingSize": {
"type": "number"
},
"servingSizeUnit": {
"type": "string",
"description": "g or ml. Foods created by the in-app assistant can also use count units such as item."
},
"servingSizeText": {
"type": "string"
}
},
"required": [
"id",
"name",
"protein",
"carbs",
"fat",
"alcohol",
"calories",
"servingSize",
"servingSizeUnit",
"servingSizeText"
],
"additionalProperties": true
}
},
"required": [
"created",
"customFood"
],
"additionalProperties": true
}Example request
The REST example uses OpenSSL to generate a fresh key for a new create. To retry that create, rerun only the curl command with the same key and input. You may send that key as idempotency_key in the MCP arguments too.
DAILYGOAL_IDEMPOTENCY_KEY="$(openssl rand -hex 16)"
curl -X POST "https://api.dailygoal.fit/v1/custom-foods" \
-H "Authorization: Bearer $DAILYGOAL_API_TOKEN" \
-H "Idempotency-Key: $DAILYGOAL_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Greek yoghurt 2%","protein":9.9,"carbs":3.9,"fat":2,"servingSize":150,"servingSizeUnit":"g","servingSizeText":"1 pot"}'{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "save_custom_food",
"arguments": {
"name": "Greek yoghurt 2%",
"protein": 9.9,
"carbs": 3.9,
"fat": 2,
"servingSize": 150,
"servingSizeUnit": "g",
"servingSizeText": "1 pot"
}
}
}Example response
Synthetic data. REST returns this object as the body; MCP returns it as structuredContent.
{
"created": true,
"customFood": {
"id": "j572k9d3m6q8x1v4n7r0t2w5b8y3h6ca",
"name": "Greek yoghurt 2%",
"protein": 9.9,
"carbs": 3.9,
"fat": 2,
"alcohol": 0,
"calories": 73.2,
"servingSize": 150,
"servingSizeUnit": "g",
"servingSizeText": "1 pot"
}
}Errors
unauthorized(401)origin_not_allowed(403)misdirected_request(421)subscription_required(403)rate_limited(429)validation_failed(400)not_found(404)conflict(409)idempotency_conflict(409)limit_exceeded(409)internal_error(500)
delete_custom_food
DELETE https://api.dailygoal.fit/v1/custom-foods
MCP tool delete_custom_food · Changes data · Destructive · DailyGoal data only
Delete one of the user's custom foods from their library. It fails with conflict while diary entries or saved meals still use the food. To remove something the user logged, use delete_food_entry instead.
Input
| Field | Type | Description |
|---|---|---|
| id | string | The custom food to delete: an id from search_foods with kind custom_food, or from save_custom_food. |
Full input schema, including bounds and nested alternatives (MCP)
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The custom food to delete: an id from search_foods with kind custom_food, or from save_custom_food."
}
},
"required": [
"id"
],
"additionalProperties": true
}Output
| Field | Type | Description |
|---|---|---|
| id | string | |
| deleted | true |
Full output schema
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"deleted": {
"type": "boolean",
"enum": [
true
]
}
},
"required": [
"id",
"deleted"
],
"additionalProperties": true
}Example request
curl -X DELETE "https://api.dailygoal.fit/v1/custom-foods?id=j572k9d3m6q8x1v4n7r0t2w5b8y3h6ca" \
-H "Authorization: Bearer $DAILYGOAL_API_TOKEN"{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_custom_food",
"arguments": {
"id": "j572k9d3m6q8x1v4n7r0t2w5b8y3h6ca"
}
}
}Example response
Synthetic data. REST returns this object as the body; MCP returns it as structuredContent.
{
"id": "j572k9d3m6q8x1v4n7r0t2w5b8y3h6ca",
"deleted": true
}Errors
unauthorized(401)origin_not_allowed(403)misdirected_request(421)subscription_required(403)rate_limited(429)validation_failed(400)not_found(404)conflict(409)internal_error(500)