FoodLens · CaloAI REST API
FoodLens API Docs
The FoodLens (CaloAI) REST API is a food image recognition API. Send one food photo, and for every food in it you get back the name, position, serving size, ingredients, calories, and 36 nutrients as JSON. This page introduces the features and the response structure.
Overview
CaloAI is the FoodLens 2.0 engine. Its response format is the same as FoodLens, and some fields (such as food groups) are filled in only by CaloAI.
Features and endpoints
Paths are relative, without the server address.
Food recognition — Send a food photo (multipart/form-data) and get back the list of recognized foods. See response
Food info — Returns the serving size and nutrition of a food by its food ID. The response format is the same as the recognition result. See response
Food search — Searches the nutrition database (more than 280,000 foods) by food name and returns a simple list (ID and name) or a detailed list (with serving size and calories). The path is given in the full specification. See response
Android · iOS SDK
To build FoodLens into an app, you can use the SDKs instead of calling the REST API. The UI SDK includes ready-made camera, result, and food search screens; the Core SDK lets you build your own screens. SDK results use the same response format as this document.
Common response format
Every response is application/json and wrapped in the structure below.
| Field | Type | Description |
|---|---|---|
| success | Boolean | Result of the request: true on success, false on failure |
| code | String | Error code when something went wrong, e.g. server.error (internal server error). Empty string on success |
| body | Array | List of results: food objects for recognition and food info, search result objects for search |
| path | String | Processing path information. Usually an empty string |
Recognition response
body contains one food object for each food in the photo. The example below is the result for one plate of prawn oil pasta (values are examples).
Food object
| Field | Type | Description |
|---|---|---|
| name | String | Base food name, e.g. Oil Pasta |
| fullName | String | Name combining the food and its ingredients, e.g. Prawn Oil Pasta |
| position | Object | Position of the food in the photo (pixels): xmin, xmax, ymin, ymax |
| candidates | Array | Candidate foods. FoodLens returns 5 and CaloAI returns 1 (multiple candidates can be requested as an option) |
| ingredients | Array | Ingredient list: name (ingredient name) and gram (weight per serving) |
Candidate object
| Field | Type | Description |
|---|---|---|
| id | Number | Food ID. -1 for CaloAI |
| manufacturer | String | Manufacturer (packaged foods and franchise menus) |
| foodName | String | Base food name |
| fullFoodName | String | Name combining the food and its ingredients |
| foodType | String | Food type (e.g. alcoholic beverage) |
| servingSize | Number | Serving size |
| totalServingSize | Number | Total package size (when available) |
| unit | String | Serving unit (g, ml) |
| counts | String | Name of the serving unit, e.g. plate(L) |
| countsDetail | Array | Unit details. countType is serving (one serving), plus total when the total package size differs. Each item has servingSize, countsValue, counts, and the secondary unit subCountsValue and subCounts |
| ingredients | Array | Ingredient list for this candidate |
| energy … | Number | Calories and nutrients. See Nutrient fields |
Missing values are returned as -1 for numbers and as an empty string for strings.
Example response
{
"body": [
{
"name": "Oil Pasta",
"fullName": "Prawn Oil Pasta",
"position": { "xmin": 27, "xmax": 712, "ymin": 43, "ymax": 508 },
"candidates": [
{
"id": -1,
"manufacturer": "",
"foodName": "Oil Pasta",
"fullFoodName": "Prawn Oil Pasta",
"foodType": "",
"servingSize": 388.0,
"totalServingSize": 388.0,
"unit": "g",
"counts": "plate(L)",
"countsDetail": [
{ "countType": "serving", "servingSize": 388.0, "countsValue": 1.0, "counts": "plate(L)", "subCountsValue": -1.0, "subCounts": "" }
],
"ingredients": [
{ "name": "Noodles", "gram": 250.0 },
{ "name": "Prawn", "gram": 80.0 },
{ "name": "Oil", "gram": 50.0 },
{ "name": "Parmesan", "gram": 5.0 },
{ "name": "Salt", "gram": 2.5 },
{ "name": "Black pepper", "gram": 0.5 }
],
"energy": 872.21,
"carbohydrate": 68.36,
"protein": 25.46,
"fat": 51.9,
"totalSugars": 0.0,
"totalDietaryFiber": 0.0,
"calcium": 117.31,
"iron": 2.96,
"magnesium": 2.55,
"phosphorus": 220.11,
"potassium": 363.71,
"sodium": 1043.66,
"zinc": 0.21,
"selenium": 1.78,
"retinol": 12.75,
"betaCarotene": 5.54,
"vitaminA": 13.21,
"thiamin": 0.15,
"riboflavin": 0.1,
"niacin": 4.27,
"vitaminB6": 0.0,
"biotin": 0.05,
"totalFolate": 0.38,
"vitaminC": 0.8,
"vitaminD": 0.03,
"vitaminE": 40.68,
"vitaminK": 86.14,
"isoleucine": 74.42,
"leucine": 141.49,
"valine": 95.69,
"bcaa": 5.21,
"cholesterol": 5.3,
"saturatedFattyAcid": 6.26,
"epa": 0.0,
"dha": 0.0,
"omega3FattyAcid": 3.41,
"omega6FattyAcid": 17.07,
"transFattyAcid": 0.04,
"grainGroup": -1.0,
"proteinGroup": -1.0,
"vegetableGroup": -1.0,
"fruitGroup": -1.0,
"oilGroup": -1.0,
"sugarGroup": -1.0,
"dairyGroup": -1.0
}
],
"ingredients": [
{ "name": "Noodles", "gram": 250.0 },
{ "name": "Prawn", "gram": 80.0 },
{ "name": "Oil", "gram": 50.0 },
{ "name": "Parmesan", "gram": 5.0 },
{ "name": "Salt", "gram": 2.5 },
{ "name": "Black pepper", "gram": 0.5 }
]
}
],
"path": "",
"success": true,
"code": ""
}
Nutrient fields
All nutrient values are per one serving (servingSize). Missing values are returned as -1.
| Field | Nutrient | Unit |
|---|---|---|
| energy | Energy (calories) | kcal |
| carbohydrate | Carbohydrate | g |
| protein | Protein | g |
| fat | Fat | g |
| totalSugars | Total sugars | g |
| totalDietaryFiber | Dietary fiber | g |
| saturatedFattyAcid | Saturated fat | g |
| transFattyAcid | Trans fat | g |
| cholesterol | Cholesterol | mg |
| sodium | Sodium | mg |
| calcium | Calcium | mg |
| iron | Iron | mg |
| magnesium | Magnesium | mg |
| phosphorus | Phosphorus | mg |
| potassium | Potassium | mg |
| zinc | Zinc | mg |
| selenium | Selenium | μg |
| vitaminA | Vitamin A | μg |
| retinol | Retinol | μg |
| betaCarotene | Beta-carotene | μg |
| thiamin | Thiamin (vitamin B1) | mg |
| riboflavin | Riboflavin (vitamin B2) | mg |
| niacin | Niacin | mg |
| vitaminB6 | Vitamin B6 | mg |
| biotin | Biotin | μg |
| totalFolate | Folate | μg |
| vitaminC | Vitamin C | mg |
| vitaminD | Vitamin D | μg |
| vitaminE | Vitamin E | mg |
| vitaminK | Vitamin K | μg |
| isoleucine | Isoleucine | mg |
| leucine | Leucine | mg |
| valine | Valine | mg |
| bcaa | BCAA (branched-chain amino acids) | mg |
| epa | EPA | mg |
| dha | DHA | mg |
| omega3FattyAcid | Omega-3 fatty acids | g |
| omega6FattyAcid | Omega-6 fatty acids | g |
| grainGroup … dairyGroup | Food exchange groups (grains, protein foods, vegetables, fruits, fats and oils, sugars, dairy) | Exchange units. CaloAI only |
Food info response
Looking up a food by ID returns that one food in the same format as the recognition response. Since there is no photo, every position value is 0 and ingredients is an empty list.
{
"body": [
{
"name": "Oil Pasta",
"fullName": "Prawn Oil Pasta",
"position": { "xmin": 0, "xmax": 0, "ymin": 0, "ymax": 0 },
"candidates": [
{
"id": -1,
"manufacturer": "",
"foodName": "Oil Pasta",
"fullFoodName": "Prawn Oil Pasta",
"foodType": "",
"servingSize": 388.0,
"totalServingSize": 0.0,
"unit": "g",
"counts": "plate(L)",
"countsDetail": [
{ "countType": "serving", "servingSize": 388.0, "countsValue": 1.0, "counts": "plate(L)", "subCountsValue": -1.0, "subCounts": "" }
],
"energy": 872.21,
"carbohydrate": 68.36,
"protein": 25.46,
"fat": 51.9,
"totalSugars": 0.0,
"totalDietaryFiber": 0.0,
"sodium": 1043.66,
"cholesterol": 5.3,
"saturatedFattyAcid": 6.26,
"transFattyAcid": 0.04,
"grainGroup": -1.0,
"proteinGroup": -1.0,
"vegetableGroup": -1.0,
"fruitGroup": -1.0,
"oilGroup": -1.0,
"sugarGroup": -1.0,
"dairyGroup": -1.0
}
],
"ingredients": []
}
],
"path": "",
"success": true,
"code": ""
}
The example shows only some nutrients to save space. Actual responses include every field listed in Nutrient fields.
Food search response
The food names, IDs, and values below are examples that show the format.
Simple list
Returns only the food ID, name, and manufacturer. Get the details of the chosen food with Food info.
{
"body": [
{ "id": 6699, "foodName": "Steamed Steak", "manufacturer": "" },
{ "id": 6702, "foodName": "Grilled Sirloin Steak", "manufacturer": "" },
{ "id": 789, "foodName": "Pork Chop Steak", "manufacturer": "" }
],
"success": true,
"code": ""
}
Detailed list
Also returns the serving size, calories, and serving unit. Numeric values are returned as strings. Names and units come in the result language; the example below shows Korean results.
{
"body": [
{ "id": 360021, "foodName": "연어", "manufacturer": "부경수산", "weight": "100g", "energy": "261.0", "countsValue": "1", "counts": "총 내용량", "subCountsValue": "", "subCounts": "" },
{ "id": 94911, "foodName": "연어초밥", "manufacturer": "", "weight": "180g", "energy": "287.5", "countsValue": "1", "counts": "인분", "subCountsValue": "6", "subCounts": "개" },
{ "id": 94912, "foodName": "연어감자조림", "manufacturer": "", "weight": "125g", "energy": "140.24", "countsValue": "1", "counts": "접시(중)", "subCountsValue": "", "subCounts": "" }
],
"success": true,
"code": ""
}
Error responses
| HTTP status | Meaning |
|---|---|
| 401 Unauthorized | Credentials are missing or invalid |
| 402 Payment Required | The call limit was exceeded or payment is required |
| 403 Forbidden | The feature called is not included in the contract |
| 404 Not Found | The address does not exist or is not supported |
| 406 Not Acceptable | Does not match the registered app information |
| 5xx Server Error | Unexpected server error. The body code is server.error |
Calculating values
- Ingredient weights are also per one serving.
- Value per 100 g = nutrient value × 100 ÷
servingSize - Values for the whole package: when
countsDetailhas an item withcountType: "total", convert using that item'sservingSize. - A value of
-1means no data, so do not treat it as 0.
Getting started
- Contact us at sales@doinglab.com or +82-2-6959-5657.
- After the contract, you receive the full specification with your API key, server address, and request parameters.
- Develop and validate during the 3-month free trial (up to 3,000 FoodLens calls).
- To add it to your app quickly, use the Android and iOS SDKs with Sample UI. Manuals: Android · iOS
See FoodLens pricing. To try recognition first without signing up, upload a food photo in the Diet Camera app (available in Korea).
Talk to us about the FoodLens API
We will recommend a plan for your service and share the full API specification. Every plan includes a 3-month free trial.