Menu
shell python javascript

Introduction

Welcome to January AI's Nutritional Intelligence APIs documentation. These APIs put the food and metabolic-health intelligence behind January's own products into yours: a verified database of 54+ million foods, an AI vision model that reads meals from photos, and glucose prediction that works without a sensor β€” all through one REST API.

With a single integration, your product can:

Every endpoint speaks JSON over HTTPS. Code samples in shell, Python, and JavaScript run down the dark panel on the right β€” pick your language at the top of that panel.

New here? The Quickstart below takes you from API key to your first photo scan in about a minute, and Authentication explains the two headers every call is built on.

Quickstart

Scan a photo of a meal. Replace YOUR_API_KEY with your key and run it:

curl --location 'https://partners.january.ai/v1.1/vision/foods' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: test-7f3c1a' \
--data '{
  "photoUrl": "https://i.imgur.com/bTQIGxf.png"
}'
import requests

url = 'https://partners.january.ai/v1.1/vision/foods'
headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'test-7f3c1a'
}
data = {
    "photoUrl": "https://i.imgur.com/bTQIGxf.png"
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/vision/foods',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'test-7f3c1a'
  },
  data: {
    photoUrl: 'https://i.imgur.com/bTQIGxf.png'
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

A successful response looks like this:

{
  "mealName": "Breakfast Bowl",
  "totalNutrients": {
    "calories": {
      "value": 520,
      "unit": "calories"
    },
    "protein": {
      "value": 15,
      "unit": "grams"
    },
    "carbohydrates": {
      "value": 68,
      "unit": "grams"
    }
  },
  "detections": [
    {
      "confidenceScore": "high",
      "food": {
        "name": "Oatmeal",
        "id": 789012,
        "brandName": "",
        "nutrients": {
          "calories": {
            "value": 300,
            "unit": "calories"
          }
        },
        "servings": [
          {
            "id": 45678,
            "quantity": 1,
            "unit": "cup"
          }
        ]
      }
    }
  ]
}

The photo-scan request on the right is the fastest way to confirm your credentials work end to end: it sends one meal photo to Photo Scan and returns the foods January detects in it. Don't have an API key yet? Email us to request one.

Two of this request's headers deserve a close look now, because nearly every January endpoint uses the same pair:

Requests carry other headers as well β€” Content-Type: application/json here β€” but these two do the identifying, and most endpoints require both. See Authentication for what belongs in each.

Test values

While you're experimenting, use test- followed by a few random characters you make up β€” for example x-partner-user-id: test-7f3c1a. Pick one and keep reusing it, so your trial data stays in one place and stays separate from your colleagues'.

Note what this value is not: it isn't your name, your email, or anything that identifies a person. That's the same rule your production IDs follow, so the habit you build here is the one you want to ship.

There is no separate registration step for a test value: x-partner-user-id is the user's identity in January, and any stable ID you choose becomes that identity.

Authentication

Every user-scoped request carries both headers:

curl "https://partners.january.ai/v1.1/endpoint" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-partner-user-id: YOUR_PARTNER_USER_ID"
import requests

# Replace YOUR_API_KEY with your actual API key, and
# YOUR_PARTNER_USER_ID with the end user's stable ID from your system
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID',
    'Content-Type': 'application/json'
}
const axios = require('axios');

// Replace YOUR_API_KEY with your actual API key, and
// YOUR_PARTNER_USER_ID with the end user's stable ID from your system
const headers = {
  'Authorization': 'Bearer YOUR_API_KEY',
  'x-partner-user-id': 'YOUR_PARTNER_USER_ID',
  'Content-Type': 'application/json'
};

Every request to the January AI API identifies two things:

Identity Header Changes per request?
Your organization Authorization: Bearer YOUR_API_KEY No β€” the same key on every call
The end user you are acting on behalf of x-partner-user-id: YOUR_PARTNER_USER_ID Yes β€” one value per end user

Your API key says who is calling. x-partner-user-id says whose data this call is about. Endpoints that read or write a person's data need both.

Your API key

To get an API key, email us with your request.

Include the key on every request, in an Authorization header:

Authorization: Bearer YOUR_API_KEY

A missing or invalid API key returns 401 Unauthorized. 401 means the key and nothing else.

The end user: x-partner-user-id

Endpoints that act on a person β€” photo scans, food logs, AI training, personalized glucose predictions, and the user profile endpoints β€” are performed on behalf of one of your end users. The x-partner-user-id header names that user.

x-partner-user-id: YOUR_PARTNER_USER_ID

Send an identifier that is:

Any stable ID you choose works β€” it becomes that user's identity in January. There is no separate registration call to make first.

Why the header exists

The value scopes everything January stores about that person:

Send the wrong value and you read and write the wrong person's data. Omit it on an endpoint that requires it and the request fails with 400 Bad Request.

Each endpoint's Headers table below states whether x-partner-user-id is required for that endpoint.

Lifestyle Intelligence APIs

Look up any food a user might eat β€” by name, barcode, plain-English description, or photo β€” and search restaurant menus by dish and location.

Food Search (By Name or Barcode)

import requests

url = 'https://partners.january.ai/v1.1/search/foods'
params = {
    'query': 'banana',
    'category': 'branded'
}
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}

response = requests.get(url, params=params, headers=headers)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/search/foods?query=banana&category=branded' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID'
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://partners.january.ai/v1.1/search/foods',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  params: {
    query: 'banana',
    category: 'branded'
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "totalCount": 40,
  "items": [
    {
      "id": 84222716,
      "name": "Banana",
      "brand_name": "One",
      "protein": 2,
      "energy": 160,
      "carbs": 15,
      "fat": 10,
      "fat_total_saturated": 5,
      "net_carbs": 13,
      "sodium": 20,
      "sugars": 13,
      "added_sugars": 11,
      "gi": 34.9,
      "gl": 5.2,
      "fiber": 2,
      "potassium": 170,
      "cholesterol": 2.5,
      "photo_url": null,
      "servings": [
        {
          "id": 67943292,
          "quantity": 1,
          "unit": "bar",
          "scaling_factor": 1,
          "weight_grams": 60,
          "is_primary": true
        }
      ]
    }
  ]
}

Search for food items by name or barcode from January’s verified database of 54+ million foods, including branded, grocery, and restaurant items.

HTTP Request

GET https://partners.january.ai/v1.1/search/foods

Headers

Header Required Description
Authorization Yes Bearer token for authentication
x-partner-user-id No Identifies the end user this request acts on behalf of. See Authentication.

Query Parameters

Parameter Required Description
query Optional The search term for food items
category Optional The category of food items to filter results ('branded', 'general', or 'recipe')
upc Optional The UPC representing the barcode of a food item

Response Structure

Field Type Description
totalCount number Total number of matching food items
items array Array of food item objects

Food Item Fields

Field Type Description
id number Food item ID
name string Food name
brand_name string or null Brand name, null for generic foods
protein number or null Protein (g)
energy number or null Calories (kcal)
carbs number or null Total carbohydrates (g)
fat number or null Total fat (g)
fat_total_saturated number or null Saturated fat (g)
net_carbs number or null Net carbs: carbohydrate - fiber (g)
sodium number or null Sodium (mg)
sugars number or null Total sugars (g)
added_sugars number or null Added sugars (g)
gi number or null Glycemic index
gl number or null Glycemic load
fiber number or null Fiber (g)
potassium number or null Potassium (mg)
cholesterol number or null Cholesterol (mg)
photo_url string or null Food photo URL, null if no image available
servings array Array of serving options

Serving Fields

Field Type Description
id number Serving ID
quantity number Serving quantity
unit string Serving unit description
scaling_factor number Scaling factor
weight_grams number Weight of the serving in grams
is_primary boolean Whether this is the food's primary serving (always true for this API)
import requests

url = 'https://partners.january.ai/v1.1/search/foods/nlp'
params = {
    'query': '1 banana, 1 bowl of oatmeal, glass of orange juice'
}
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}

response = requests.get(url, params=params, headers=headers)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/search/foods/nlp?query=1%20banana%2C%201%20bowl%20of%20oatmeal%2C%20glass%20of%20orange%20juice' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID'
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://partners.january.ai/v1.1/search/foods/nlp',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  params: {
    query: '1 banana, 1 bowl of oatmeal, glass of orange juice'
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "totalNutrients": {
    "calories": {
      "value": 435,
      "unit": "calories"
    },
    "protein": {
      "value": 8.5,
      "unit": "g"
    },
    "carbohydrates": {
      "value": 92,
      "unit": "g"
    },
    "totalFat": {
      "value": 18.3,
      "unit": "g"
    },
    "fiber": {
      "value": 6.1,
      "unit": "g"
    },
    "sodium": {
      "value": 320,
      "unit": "mg"
    }
  },
  "detections": [
    {
      "food": {
        "name": "Banana",
        "id": 123456,
        "brandName": "",
        "nutrients": {
          "calories": {
            "value": 105,
            "unit": "calories"
          },
          "protein": {
            "value": 1.3,
            "unit": "g"
          },
          "carbohydrates": {
            "value": 27,
            "unit": "g"
          },
          "totalFat": {
            "value": 0.4,
            "unit": "g"
          },
          "fiber": {
            "value": 3.1,
            "unit": "g"
          },
          "sodium": {
            "value": 1,
            "unit": "mg"
          }
        },
        "servings": [
          {
            "id": 78901,
            "quantity": 1,
            "unit": "medium (7\" to 7-7/8\" long)",
            "selected_quantity": 1
          }
        ]
      }
    }
  ]
}

Search for multiple foods at once by describing them in plain English β€” via voice or text.

HTTP Request

GET https://partners.january.ai/v1.1/search/foods/nlp

Headers

Header Required Description
Authorization Yes Bearer token for authentication
x-partner-user-id No Identifies the end user this request acts on behalf of. See Authentication.

Query Parameters

Parameter Required Description
query Yes The search term for food items in natural language

Response Structure

Field Type Description
totalNutrients object Sum of scaled nutrients across all detected foods
detections array One entry per detected food item

Detection Object

Field Type Description
food.name string Food name
food.id number Food item ID
food.brandName string Brand name, or empty string for generic foods
food.nutrients object Scaled nutrients for this detection (see nutrient keys below)
food.servings array Matched servings for the detection

Nutrient Keys

All nutrient values are objects with value (number) and unit (string). Fields are omitted when the source data is not available.

Key Unit Description
calories calories Energy (kcal)
protein g Protein
carbohydrates g Total carbohydrates
netCarbohydrates g Net carbs (carbohydrate - fiber)
totalFat g Total fat
saturatedFat g Saturated fat
fiber g Fiber
totalSugars g Total sugars
addedSugars g Added sugars
sodium mg Sodium

Serving Fields

Field Type Description
id number Serving ID
quantity number Serving quantity
unit string Serving unit description
selected_quantity number Detected quantity for the serving
import requests

url = 'https://partners.january.ai/v1.1/search/restaurants'
params = {
    'query': 'mcdonalds',
    'lat': 37.549,
    'lon': -121.989
}
headers = {
    'Authorization': 'Bearer YOUR_API_KEY'
}

response = requests.get(url, params=params, headers=headers)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/search/restaurants?query=mcdonalds&lat=37.549&lon=-121.989' \
--header 'Authorization: Bearer YOUR_API_KEY'
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://partners.january.ai/v1.1/search/restaurants',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  params: {
    query: 'mcdonalds',
    lat: 37.549,
    lon: -121.989
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "items": [
    {
      "type": "restaurant",
      "id": "53fc3b8a-e6bf-404d-83c8-9f42124d1bee",
      "name": "McDonald's",
      "is_chain": false,
      "distance": 8,
      "city": "San Francisco",
      "address1": "123 Main Street",
      "address2": "Suite 100"
    }
  ]
}

Search for restaurants β€” local spots and chains β€” by name, ranked by distance when you provide the user's coordinates.

HTTP Request

GET https://partners.january.ai/v1.1/search/restaurants

Headers

Header Required Description
Authorization Yes Bearer token for authentication

Query Parameters

Parameter Required Description
query Yes Restaurant name to search for. Pass an empty value to list the nearest restaurants.
lat Optional Latitude for proximity ranking
lon Optional Longitude for proximity ranking
distance Optional Search radius in meters. Default is 16093 (~10 miles)
limit Optional Maximum number of results to return. Default is 50

Response Structure

The response includes:

import requests

url = 'https://partners.january.ai/v1.1/search/restaurants/menu'
params = {
    'query': 'burger',
    'lat': 37.549,
    'lon': -121.989
}
headers = {
    'Authorization': 'Bearer YOUR_API_KEY'
}

response = requests.get(url, params=params, headers=headers)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/search/restaurants/menu?query=burger&lat=37.549&lon=-121.989' \
--header 'Authorization: Bearer YOUR_API_KEY'
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://partners.january.ai/v1.1/search/restaurants/menu',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  params: {
    query: 'burger',
    lat: 37.549,
    lon: -121.989
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "items": [
    {
      "type": "menu_item",
      "id": "228990954",
      "name": "burger",
      "restaurant_name": "morning due cafe",
      "is_chain": false,
      "data_source_id": 12,
      "source_original_id": "ngxZD7tEA1cQGCuOYBF05Ckft2ZP3z3Ja88wVaXYqqr7P7F3QiGFN1BSCl6H0Bt_5iN7y",
      "protein": 48,
      "energy": 800,
      "carbs": 40,
      "net_carbs": 38,
      "sugars": 6,
      "added_sugars": null,
      "fat": 45,
      "gi": 48.507698,
      "gl": 36.67089,
      "fiber": 2,
      "photo_url": "https://cdn-img.ai/23361362e6a706567",
      "servings": [
        {
          "id": 189343592,
          "scaling_factor": 1,
          "quantity": 1,
          "unit": "serving",
          "weight_grams": null,
          "is_primary": true
        }
      ],
      "distance": 124
    }
  ]
}

Search for dishes across the menus of restaurants near a location β€” every "burger" within ten miles, with nutrition data for each match.

HTTP Request

GET https://partners.january.ai/v1.1/search/restaurants/menu

Headers

Header Required Description
Authorization Yes Bearer token for authentication

Query Parameters

Parameter Required Description
query Yes Dish or restaurant name to search for
lat Yes Latitude to search around
lon Yes Longitude to search around
distance Optional Search radius in meters. Default is 16093 (~10 miles)
limit Optional Maximum number of results to return. Default is 50

Response Structure

The response includes:

Photo Scan

import requests
import json

url = 'https://partners.january.ai/v1.1/vision/foods'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}
data = {
    "photoUrl": "https://i.imgur.com/bTQIGxf.png"
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/vision/foods' \
--header 'Content-Type: application/json' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
  "photoUrl": "https://i.imgur.com/bTQIGxf.png"
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/vision/foods',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  data: {
    photoUrl: 'https://i.imgur.com/bTQIGxf.png'
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "mealName": "Breakfast Bowl",
  "totalNutrients": {
    "calories": {
      "value": 520,
      "unit": "calories"
    },
    "protein": {
      "value": 15,
      "unit": "grams"
    },
    "carbohydrates": {
      "value": 68,
      "unit": "grams"
    }
  },
  "detections": [
    {
      "confidenceScore": "high",
      "food": {
        "name": "Oatmeal",
        "id": 789012,
        "brandName": "",
        "nutrients": {
          "calories": {
            "value": 300,
            "unit": "calories"
          }
        },
        "servings": [
          {
            "id": 45678,
            "quantity": 1,
            "unit": "cup"
          }
        ]
      }
    }
  ]
}

Scan a photo of a meal to identify and retrieve nutritional data for the foods detected.

HTTP Request

POST https://partners.january.ai/v1.1/vision/foods

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Request Body

Parameter Required Description
photoUrl No The URL of the image to be analyzed
photoBase64 No Base64 encoded image data (if not using photoUrl)

Photo Requirements

Response Structure

The response includes:

Edit Photo Scan Results

import requests
import json

url = 'https://partners.january.ai/v1.1/vision/fix-ai'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}
data = {
  "mealName": "Breakfast Bowl",
  "detections": [
    {
      "confidenceScore": "high",
      "food": {
        "name": "Oatmeal",
        "id": 789012,
        "brandName": null,
        "nutrients": {
          "calories": {
            "value": 300,
            "unit": "kcal"
          }
        },
        "servings": [
          {
            "id": 45678,
            "quantity": 1,
            "unit": "cup"
          }
        ]
      }
    }
  ],
  "userInput": "change oatmeal to steel-cut oats"
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/vision/fix-ai' \
--header 'Content-Type: application/json' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
  "mealName": "Breakfast Bowl",
  "detections": [
    {
      "confidenceScore": "high",
      "food": {
        "name": "Oatmeal",
        "id": 789012,
        "brandName": null,
        "nutrients": {
          "calories": {
            "value": 300,
            "unit": "kcal"
          }
        },
        "servings": [
          {
            "id": 45678,
            "quantity": 1,
            "unit": "cup"
          }
        ]
      }
    }
  ],
  "userInput": "change oatmeal to steel-cut oats"
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/vision/fix-ai',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  data: {
    "mealName": "Breakfast Bowl",
    "detections": [
      {
        "confidenceScore": "high",
        "food": {
          "name": "Oatmeal",
          "id": 789012,
          "brandName": null,
          "nutrients": {
            "calories": {
              "value": 300,
              "unit": "kcal"
            }
          },
          "servings": [
            {
              "id": 45678,
              "quantity": 1,
              "unit": "cup"
            }
          ]
        }
      }
    ],
    "userInput": "change oatmeal to steel-cut oats"
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "mealName": "Breakfast Bowl",
  "totalNutrients": {
    "calories": {
      "value": 520,
      "unit": "kcal"
    },
    "carbs": {
      "value": 68,
      "unit": "g"
    },
    "protein": {
      "value": 15,
      "unit": "g"
    }
  },
  "detections": [
    {
      "confidenceScore": "high",
      "food": {
        "name": "Oatmeal",
        "id": 789012,
        "brandName": null,
        "nutrients": {
          "calories": {
            "value": 300,
            "unit": "kcal"
          }
        },
        "servings": [
          {
            "id": 45678,
            "quantity": 1,
            "unit": "cup"
          }
        ]
      }
    }
  ]
}

Lets a user correct a photo scan in natural language, by voice or text. For example, after scanning a chicken and rice bowl and spotting a couple of inaccuracies, a user might say:

"It was actually 1 cup of chicken. It was also white rice, not brown rice."

The API parses this input and updates the scan results accordingly.

HTTP Request

POST https://partners.january.ai/v1.1/vision/fix-ai

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Request Body

Parameter Required Description
mealName Yes Name of the meal to edit
detections Yes Array of detected food items to edit
userInput Yes Text representation of changes to make

Response Structure

The response includes:

Food Logging APIs

Write to and read from each user's food diary β€” the history that grounds January's personalized predictions.

Create Food Logs

import requests
import json

url = 'https://partners.january.ai/v1.1/logs/foods'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}
data = {
    "foods": [
        {
            "id": 101963552,
            "serving": {
                "id": 68051535,
                "quantity": 1.4
            }
        }
    ],
    "timestampUtc": "2024-09-13T11:34:56Z"
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/logs/foods' \
--header 'Content-Type: application/json' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
  "foods": [
    {
      "id": 101963552,
      "serving": {
        "id": 68051535,
        "quantity": 1.4
      }
    }
  ],
  "timestampUtc": "2024-09-13T11:34:56Z"
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/logs/foods',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  data: {
    foods: [
      {
        id: 101963552,
        serving: {
          id: 68051535,
          quantity: 1.4
        }
      }
    ],
    timestampUtc: "2024-09-13T11:34:56Z"
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

Log one or more foods to a user's food diary at a given time. Food and serving IDs come from the search and photo scan endpoints.

HTTP Request

POST https://partners.january.ai/v1.1/logs/foods

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Request Body

Parameter Required Description
foods Yes Array of food items to be logged
foods[].id Yes Unique identifier of the food item
foods[].serving Yes Serving details of the food item
foods[].serving.id Yes Serving size identifier
foods[].serving.quantity Yes Amount of the serving consumed
timestampUtc Yes UTC timestamp when food was consumed (YYYY-MM-DDTHH:MM:SSZ)
name Optional Name of the meal

Retrieve Food Logs

import requests

url = 'https://partners.january.ai/v1.1/logs/foods'
params = {
    'start': '2023-09-12',
    'end': '2024-09-15'
}
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}

response = requests.get(url, params=params, headers=headers)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/logs/foods?start=2023-09-12&end=2024-09-15' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--header 'Authorization: Bearer YOUR_API_KEY'
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://partners.january.ai/v1.1/logs/foods',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  params: {
    start: '2023-09-12',
    end: '2024-09-15'
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

Retrieve a user's food logs over a date range.

HTTP Request

GET https://partners.january.ai/v1.1/logs/foods

Headers

Header Required Description
Authorization Yes Bearer token for authentication
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Query Parameters

Parameter Required Description
start Yes Start date (YYYY-MM-DD format)
end Yes End date (YYYY-MM-DD format)

Delete Food Log

import requests

url = 'https://partners.january.ai/v1.1/logs/foods/78129823-8ba2-4183-b13b-71f0e963c606'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}

response = requests.delete(url, headers=headers)
print(response.status_code)
curl --location --request DELETE 'https://partners.january.ai/v1.1/logs/foods/78129823-8ba2-4183-b13b-71f0e963c606' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--header 'Authorization: Bearer YOUR_API_KEY'
const axios = require('axios');

const config = {
  method: 'delete',
  url: 'https://partners.january.ai/v1.1/logs/foods/78129823-8ba2-4183-b13b-71f0e963c606',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  }
};

axios(config)
  .then(response => {
    console.log(response.status);
  })
  .catch(error => {
    console.log(error);
  });

Delete a single food log entry by its ID.

HTTP Request

DELETE https://partners.january.ai/v1.1/logs/foods/{logId}

URL Parameters

Parameter Description
logId The unique identifier of the food log to delete

Headers

Header Required Description
Authorization Yes Bearer token for authentication
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Glucose Insights APIs

Predict how a meal will move a user's glucose β€” before they take the first bite.

There are two ways to get a prediction, and they differ in what you have to set up first:

The endpoints between the two below β€” Create User, Get and Update User Profile, and Mark User as AI-Trained β€” exist to support the personalized path. They store the profile and training history that AI-Trained Glucose Prediction reads from. If you are only using the stateless prediction, food search, photo scan, or food logging, you do not need any of them.

Glucose Prediction

import requests
import json

url = 'https://partners.january.ai/v1.1/cgm/glucose-predict'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-timezone': 'America/Los_Angeles'
}
data = {
    "userProfile": {
        "age": 25,
        "gender": "male",
        "height": 65,
        "weight": 165,
        "activity_level": "very_active",
        "medical_conditions": ["Type 2 diabetes"]
    },
    "startTime": "2025-04-09T19:06:12Z",
    "foods": [
        {
            "id": 70380652,
            "serving": {
                "id": 34176931,
                "quantity": 1
            }
        }
    ],
    "cgmData": [
        # Optional CGM data array
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "value": 92
        },
        {
            "timestamp": "2025-04-03T14:59:40Z",
            "value": 95
        }
    ],
    "consumedFoods": [
        # Optional historical user foods
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "id": 70380652,
            "serving": {
                "id": 34176931,
                "quantity": 1
            }
        }
    ]
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/cgm/glucose-predict' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-timezone: America/Los_Angeles' \
--data '{
  "userProfile": {
    "age": 25,
    "gender": "male",
    "height": 65,
    "weight": 165,
    "activity_level": "very_active",
    "medical_conditions": ["Type 2 diabetes"]
  },
  "startTime": "2025-04-09T19:06:12Z",
  "foods": [
    {
      "id": 70380652,
      "serving": {
        "id": 34176931,
        "quantity": 1
      }
    }
  ],
  "cgmData": [
    {
      "timestamp": "2025-04-03T14:56:03Z",
      "value": 92
    },
    {
      "timestamp": "2025-04-03T14:59:40Z",
      "value": 95
    }
  ],
  "consumedFoods": [
    {
      "timestamp": "2025-04-03T14:56:03Z",
      "id": 70380652,
      "serving": {
          "id": 34176931,
          "quantity": 1
      }
    }
  ]
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/cgm/glucose-predict',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-timezone': 'America/Los_Angeles'
  },
  data: {
    userProfile: {
      age: 25,
      gender: "male",
      height: 65,
      weight: 165,
      activity_level: "very_active",
      medical_conditions: ["Type 2 diabetes"]
    },
    startTime: "2025-04-09T19:06:12Z",
    foods: [
      {
        id: 70380652,
        serving: {
          id: 34176931,
          quantity: 1
        }
      }
    ],
    cgmData: [
        // Optional CGM data array
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "value": 92
        }
    ],
    consumedFoods: [
        // Optional historical user foods
        {
            timestamp: "2025-04-03T14:56:03Z",
            id: 70380652,
            serving: {
                id: 34176931,
                quantity: 1
            }
        }
    ]
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "cgp": [
    [0, 95],
    [15, 110],
    [30, 140],
    [45, 155],
    [60, 145],
    [75, 125],
    [90, 110],
    [105, 100],
    [120, 95],
    [135, 92]
  ],
  "scoring": "medium_impact",
  "cgp_min": 70,
  "cgp_max": 140
}

Returns a two-hour glucose response curve for a meal, computed from the user's profile and the foods in the request. Nothing is stored β€” the profile travels with every call.

You can optionally provide cgmData and consumedFoods to personalize the prediction with the user's own history. To count as training data, the input must include at least five complete training days.

A training day is complete when it meets both of the following criteria:

HTTP Request

POST https://partners.january.ai/v1.1/cgm/glucose-predict

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-timezone Yes User local timezone (e.g. America/New_York or US/Pacific)

Request Body

Parameter Required Description
userProfile Yes User's profile data
userProfile.age Yes User's age
userProfile.gender Yes User's gender ('male' or 'female')
userProfile.height Yes User's height in inches
userProfile.weight Yes User's weight in pounds
userProfile.activity_level No Activity level ('sedentary', 'lightly_active', 'moderately_active', 'very_active')
userProfile.medical_conditions No Array of medical conditions (excluding 'Type 1 diabetes')
foods Yes Array of foods and servings for prediction
foods[].id Yes Unique identifier of the food item
foods[].serving Yes Serving details
foods[].serving.id Yes Serving size identifier
foods[].serving.quantity Yes Amount of serving consumed
startTime Yes ISO 8601 timestamp for when foods are consumed
cgmData No CGM data array for AI training. Please provide at least one data point per 15 minutes. If cgmData is provided, consumedFoods must be provided also.
cgmData[].timestamp Yes ISO 8601 timestamp for the CGM data point
cgmData[].value Yes Blood sugar level (in mg/dL)
consumedFoods No Array of historical user foods and servings for AI training.
consumedFoods[].timestamp Yes ISO 8601 timestamp for when the food is consumed
consumedFoods[].id Yes Unique identifier of the food item
consumedFoods[].serving Yes Serving details
consumedFoods[].serving.id Yes Serving size identifier
consumedFoods[].serving.quantity Yes Amount of serving consumed

Medical Conditions

Valid medical conditions include:

Response Structure

The response includes:

Set Up a User for Personalized Predictions

The three endpoints that follow β€” Create User, Mark User as AI-Trained, and the profile read/update pair β€” prepare a user for AI-Trained Glucose Prediction.

The sequence is:

  1. Create User with the user's profile. Store the returned user_id.
  2. Mark User as AI-Trained with at least five valid training days of CGM and meal data.
  3. AI-Trained Glucose Prediction using that user_id as the x-partner-user-id.

Create User

import requests
import json

url = 'https://partners.january.ai/v1.1/user'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}
data = {
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/user' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/user',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  data: {
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
    "user_id": "a88888ef-cc9c-5882-ba2c-9cbee8a4b73c",
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}

Creates a January user with the profile the glucose prediction endpoints rely on β€” age, gender, height, and weight β€” and returns the generated user_id.

HTTP Request

POST https://partners.january.ai/v1.1/user

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json

Request Body

Parameter Required Description
profile Yes User profile object
profile.age Yes User's age
profile.gender Yes User's gender ('male' or 'female')
profile.height Yes User's height in inches
profile.weight Yes User's weight in pounds
profile.activity_level No Activity level ('sedentary', 'lightly_active', 'moderately_active', 'very_active')
profile.medical_conditions No Array of medical conditions

Medical Conditions

Valid medical conditions include:

Response Structure

The response includes:

Get User Profile

import requests
import json

url = 'https://partners.january.ai/v1.1/user'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}

response = requests.get(url, headers=headers)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/user' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID'
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://partners.january.ai/v1.1/user',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
    "user_id": "a88888ef-cc9c-5882-ba2c-9cbee8a4b73c",
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}

Returns the user's ID and stored profile. If January has no user under the x-partner-user-id you sent, the request returns 404 Not Found.

HTTP Request

GET https://partners.january.ai/v1.1/user

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Response Structure

The response includes:

Update User Profile

import requests
import json

url = 'https://partners.january.ai/v1.1/user'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}
data = {
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}

response = requests.patch(url, headers=headers, json=data)
print(response.json())
curl --location --request PATCH 'https://partners.january.ai/v1.1/user' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--data '{
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}'
const axios = require('axios');

const config = {
  method: 'patch',
  url: 'https://partners.january.ai/v1.1/user',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  data: {
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
    "user_id": "a88888ef-cc9c-5882-ba2c-9cbee8a4b73c",
    "profile": {
        "age": 20,
        "gender": "male",
        "weight": 80,
        "height": 36,
        "activity_level": "sedentary",
        "medical_conditions": []
    }
}

Updates the user's stored profile and returns the updated record.

HTTP Request

PATCH https://partners.january.ai/v1.1/user

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.

Request Body

Parameter Required Description
profile Yes User profile object
profile.age Yes User's age
profile.gender Yes User's gender ('male' or 'female')
profile.height Yes User's height in inches
profile.weight Yes User's weight in pounds
profile.activity_level No Activity level ('sedentary', 'lightly_active', 'moderately_active', 'very_active')
profile.medical_conditions No Array of medical conditions

Medical Conditions

Valid medical conditions include:

Response Structure

The response includes:

Mark User as AI-Trained

import requests
import json

url = 'https://partners.january.ai/v1.1/user/training'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
}
data = {
    "cgm_data": [
        # CGM data array
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "value": 92
        },
        {
            "timestamp": "2025-04-03T14:59:40Z",
            "value": 95
        }
    ],
    "consumed_foods": [
        # Historical user foods
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "id": 70380652,
            "serving": {
                "id": 34176931,
                "quantity": 1
            }
        }
    ]
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/user/training' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--data '{
    "cgm_data": [
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "value": 92
        },
        {
            "timestamp": "2025-04-03T14:59:40Z",
            "value": 95
        }
    ],
    "consumed_foods": [
        {
            "timestamp": "2025-04-03T14:56:03Z",
            "id": 70380652,
            "serving": {
                "id": 34176931,
                "quantity": 1
            }
        }
    ]
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/user/training',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID'
  },
  data: {
    "cgm_data": [
      // CGM data array
      {
        "timestamp": "2025-04-03T14:56:03Z",
        "value": 92
      },
      {
        "timestamp": "2025-04-03T14:59:40Z",
        "value": 95
      }
    ],
    "consumed_foods": [
      // Historical user foods
      {
        "timestamp": "2025-04-03T14:56:03Z",
        "id": 70380652,
        "serving": {
          "id": 34176931,
          "quantity": 1
        }
      }
    ]
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
    "good_days": [
        "2025-09-01",
        "2025-09-02",
        "2025-09-03",
        "2025-09-04",
        "2025-09-05"
    ]
}

Submits a user's historical CGM and meal data to train their personalized glucose model.

Both cgm_data and consumed_foods are required, with enough data to complete training: five or more valid training days.

A valid training day must include:

If the data does not meet these requirements, the endpoint returns a 400 Bad Request error.

HTTP Request

POST https://partners.january.ai/v1.1/user/training

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.
x-partner-timezone Yes User local timezone (e.g. America/New_York or US/Pacific)

Request Body

Parameter Required Description
cgm_data Yes CGM data array for AI training. Please provide at least one data point per 15 minutes.
cgm_data[].timestamp Yes ISO 8601 timestamp for the CGM data point
cgm_data[].value Yes Blood sugar level (in mg/dL)
consumed_foods Yes Array of historical user foods and servings for AI training.
consumed_foods[].timestamp Yes ISO 8601 timestamp for when the food is consumed
consumed_foods[].id Yes Unique identifier of the food item
consumed_foods[].serving Yes Serving details
consumed_foods[].serving.id Yes Serving size identifier
consumed_foods[].serving.quantity Yes Amount of serving consumed

Response Structure

The response includes:

AI-Trained Glucose Prediction

import requests
import json

url = 'https://partners.january.ai/v1.1/cgm/user-glucose-predict'
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID',
    'x-partner-timezone': 'America/Los_Angeles'
}
data = {
    "startTime": "2025-04-09T19:06:12Z",
    "foods": [
        {
            "id": 70380652,
            "serving": {
                "id": 34176931,
                "quantity": 1
            }
        }
    ]
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
curl --location 'https://partners.january.ai/v1.1/cgm/user-glucose-predict' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'x-partner-user-id: YOUR_PARTNER_USER_ID' \
--header 'x-partner-timezone: America/Los_Angeles' \
--data '{
  "startTime": "2025-04-09T19:06:12Z",
  "foods": [
    {
      "id": 70380652,
      "serving": {
        "id": 34176931,
        "quantity": 1
      }
    }
  ]
}'
const axios = require('axios');

const config = {
  method: 'post',
  url: 'https://partners.january.ai/v1.1/cgm/user-glucose-predict',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-partner-user-id': 'YOUR_PARTNER_USER_ID',
    'x-partner-timezone': 'America/Los_Angeles'
  },
  data: {
    startTime: "2025-04-09T19:06:12Z",
    foods: [
      {
        id: 70380652,
        serving: {
          id: 34176931,
          quantity: 1
        }
      }
    ]
  }
};

axios(config)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });

The above command returns JSON structured like this:

{
  "cgp": [
    [0, 95],
    [15, 110],
    [30, 140],
    [45, 155],
    [60, 145],
    [75, 125],
    [90, 110],
    [105, 100],
    [120, 95],
    [135, 92]
  ],
  "scoring": "medium_impact",
  "cgp_min": 70,
  "cgp_max": 140
}

Returns a two-hour glucose prediction using a personalized AI model trained on a specific user's CGM and meal history.

Pass the end user in the x-partner-user-id header, as with every user-scoped endpoint. Unlike the others, this one requires that the user has already completed AI training β€” see Mark User as AI-Trained.

Accepts either the foods or nutrients parameter as input. Unlike the standard glucose prediction endpoint, this version does not require passing CGM data in the request β€” improving performance by using previously stored training data.

HTTP Request

POST https://partners.january.ai/v1.1/cgm/user-glucose-predict

Headers

Header Required Description
Authorization Yes Bearer token for authentication
Content-Type Yes Must be application/json
x-partner-user-id Yes Identifies the end user this request acts on behalf of. See Authentication.
x-partner-timezone Yes User local timezone (e.g. America/New_York or US/Pacific)

Request Body

Parameter Required Description
startTime No ISO 8601 timestamp for when foods are consumed (default is current time)
foods No Array of foods and servings for prediction. If not specified, then nutrients parameter is applied.
foods[].id Yes Unique identifier of the food item
foods[].serving Yes Serving details
foods[].serving.id Yes Serving size identifier
foods[].serving.quantity Yes Amount of serving consumed
nutrients No Object with nutrients quantities (applied only when foods parameter is not specified)
nutrients.water No Quantity of water (g)
nutrients.energy No Quantity of energy (calories)
nutrients.protein No Quantity of protein (g)
nutrients.fat_total_lipid No Quantity of total fat (g)
nutrients.carbohydrate No Quantity of carbohydrates (g)
nutrients.fiber No Quantity of fiber (g)
nutrients.sugars No Quantity of sugars (g)
nutrients.calcium No Quantity of calcium (g)
nutrients.iron No Quantity of iron (g)
nutrients.potassium No Quantity of potassium (g)
nutrients.sodium No Quantity of sodium (mg)
nutrients.vit_c No Quantity of vit C (g)
nutrients.vit_a_iu No Quantity of vit A iu (g)
nutrients.fat_total_saturated No Quantity of saturated fat (g)
nutrients.fat_total_monounsaturated No Quantity of monounsaturated fat (g)
nutrients.fat_total_polyunsaturated No Quantity of polyunsaturated fat (g)
nutrients.fat_total_trans No Quantity of trans fat (g)
nutrients.cholesterol No Quantity of cholesterol (g)
nutrients.caffeine No Quantity of caffeine (g)

Response Structure

The response includes:

Errors

The January AI API uses conventional HTTP status codes:

Error Code Meaning
400 Bad Request -- Your request is invalid or malformed. Most often this means the x-partner-user-id header is missing on an endpoint that requires it β€” see Missing x-partner-user-id (400).
401 Unauthorized -- Your API key is invalid or missing.
403 Forbidden -- You don't have permission to access this resource.
404 Not Found -- The specified resource could not be found.
405 Method Not Allowed -- You tried to access a resource with an invalid HTTP method.
406 Not Acceptable -- You requested a format that isn't supported.
422 Unprocessable Entity -- The request was well-formed but contains semantic errors.
429 Too Many Requests -- You're sending requests too quickly. Slow down and retry.
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

Error Response Format

Error responses are formatted like this:

{
  "message": "The 'query' parameter is required for this endpoint."
}

All error responses follow the same format: an object with a single top-level message field.

Common Error Scenarios

Authentication Errors

Request Errors

Server Errors

Missing x-partner-user-id (400)

A user-scoped endpoint called without the x-partner-user-id header returns:

{
  "message": "The x-partner-user-id header is required for this endpoint. It identifies the end user this request is performed on behalf of. Use a stable ID from your system. See https://docs.january.ai/#authentication."
}

A valid API key alone is not enough on endpoints that act on a person. If the x-partner-user-id header is missing or empty on one of those endpoints, the request fails with 400 Bad Request and the message string above.

This is not an API key problem. Your key was accepted β€” the request just didn't say which end user it was for. Add the header and retry:

x-partner-user-id: YOUR_PARTNER_USER_ID

See Authentication for what value to send, and each endpoint's Headers table for whether it requires the header.

Questions?

If anything in these docs is unclear β€” or the API returns something they don't explain β€” email umer@january.ai. Don't hesitate to reach out; we're happy to help.