Code Examples

Complete, working examples for integrating the NutrientAPI nutrition analysis endpoint. Every example below includes error handling and response parsing.

API Endpoint:
POST https://api.nutrientapi.com/v1/analyze
Authentication: Bearer token via the Authorization header.
Content-Type: application/json

Request Format

All examples below send the same request body:

{
  "title": "Avocado Toast",
  "ingredients": [
    "2 slices whole wheat bread",
    "1 medium avocado",
    "1 tbsp lemon juice",
    "1/4 tsp salt",
    "pinch of red pepper flakes"
  ],
  "servings": 2
}

Response Format

The API returns a JSON object with this structure:

{
  "status": "success",
  "ingredients": [
    {
      "parsed": "whole wheat bread",
      "confidence": 0.95,
      "nutrients": {
        "calories": 160.4,
        "protein": 7.8,
        "fat": 2.4,
        "carbs": 27.6,
        // ... 10 more nutrients
      }
    }
    // ... more ingredients
  ],
  "totals": { /* sum of all ingredients */ },
  "per_serving": { /* totals divided by servings */ },
  "diet_labels": ["VEGAN", "VEGETARIAN"],
  "health_labels": ["DAIRY_FREE", "EGG_FREE"]
}

curl

curl -X POST https://api.nutrientapi.com/v1/analyze \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "title": "Avocado Toast",
    "ingredients": [
      "2 slices whole wheat bread",
      "1 medium avocado",
      "1 tbsp lemon juice",
      "1/4 tsp salt",
      "pinch of red pepper flakes"
    ],
    "servings": 2
  }'

Python

Uses the requests library. Install with pip install requests.

import requests
import os
import sys

API_KEY = os.environ["NUTRIENTAPI_KEY"]
API_URL = "https://api.nutrientapi.com/v1/analyze"


def analyze_recipe(title, ingredients, servings=1):
    """Analyze a recipe and return nutrition data.

    Args:
        title: Recipe name (e.g. "Avocado Toast").
        ingredients: List of ingredient strings in natural language.
        servings: Number of servings the recipe makes.

    Returns:
        Parsed JSON response with nutrients, totals, and labels.

    Raises:
        requests.HTTPError: If the API returns a non-2xx status.
    """
    response = requests.post(
        API_URL,
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer {API_KEY}",
        },
        json={
            "title": title,
            "ingredients": ingredients,
            "servings": servings,
        },
        timeout=30,
    )
    response.raise_for_status()
    return response.json()


# --- Example usage ---

result = analyze_recipe(
    title="Avocado Toast",
    ingredients=[
        "2 slices whole wheat bread",
        "1 medium avocado",
        "1 tbsp lemon juice",
        "1/4 tsp salt",
        "pinch of red pepper flakes",
    ],
    servings=2,
)

# Print per-serving summary
per_serving = result["per_serving"]
print(f"Per serving: {per_serving['calories']:.0f} cal, "
      f"{per_serving['protein']:.1f}g protein, "
      f"{per_serving['fat']:.1f}g fat, "
      f"{per_serving['carbs']:.1f}g carbs")

# Print labels
print(f"Diet labels: {', '.join(result['diet_labels'])}")
print(f"Health labels: {', '.join(result['health_labels'])}")

# Check confidence scores -- flag ingredients below threshold
for ing in result["ingredients"]:
    if ing["confidence"] < 0.8:
        print(f"Low confidence ({ing['confidence']:.2f}): {ing['parsed']}")

Error Handling (Python)

import requests

try:
    result = analyze_recipe(
        title="Avocado Toast",
        ingredients=["2 slices whole wheat bread", "1 medium avocado"],
        servings=2,
    )
except requests.exceptions.HTTPError as e:
    if e.response.status_code == 401:
        print("Invalid API key. Check your NUTRIENTAPI_KEY.")
    elif e.response.status_code == 422:
        print(f"Validation error: {e.response.json()}")
    elif e.response.status_code == 429:
        print("Rate limited. Back off and retry.")
    else:
        print(f"API error {e.response.status_code}: {e.response.text}")
except requests.exceptions.Timeout:
    print("Request timed out. Try again.")
except requests.exceptions.ConnectionError:
    print("Could not connect to the API.")

JavaScript (Fetch API)

Works in browsers and modern JavaScript runtimes.

const API_KEY = "YOUR_API_KEY";
const API_URL = "https://api.nutrientapi.com/v1/analyze";

async function analyzeRecipe(title, ingredients, servings = 1) {
  const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${API_KEY}`,
    },
    body: JSON.stringify({ title, ingredients, servings }),
  });

  if (!response.ok) {
    const errorBody = await response.text();
    throw new Error(`API error ${response.status}: ${errorBody}`);
  }

  return response.json();
}

// --- Example usage ---

try {
  const result = await analyzeRecipe(
    "Avocado Toast",
    [
      "2 slices whole wheat bread",
      "1 medium avocado",
      "1 tbsp lemon juice",
      "1/4 tsp salt",
      "pinch of red pepper flakes",
    ],
    2
  );

  // Per-serving summary
  const ps = result.per_serving;
  console.log(
    `Per serving: ${Math.round(ps.calories)} cal, ` +
    `${ps.protein.toFixed(1)}g protein, ` +
    `${ps.fat.toFixed(1)}g fat, ` +
    `${ps.carbs.toFixed(1)}g carbs`
  );

  // Labels
  console.log("Diet labels:", result.diet_labels.join(", "));
  console.log("Health labels:", result.health_labels.join(", "));

  // Check for low-confidence ingredients
  result.ingredients
    .filter((ing) => ing.confidence < 0.8)
    .forEach((ing) => {
      console.warn(`Low confidence (${ing.confidence}): ${ing.parsed}`);
    });
} catch (error) {
  console.error("Failed to analyze recipe:", error.message);
}

Node.js

Uses the built-in fetch available in Node.js 18+. For older versions, install node-fetch.

const API_KEY = process.env.NUTRIENTAPI_KEY;
const API_URL = "https://api.nutrientapi.com/v1/analyze";

async function analyzeRecipe(title, ingredients, servings = 1) {
  const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${API_KEY}`,
    },
    body: JSON.stringify({ title, ingredients, servings }),
  });

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`NutrientAPI error ${response.status}: ${body}`);
  }

  return response.json();
}

// --- Example: Analyze and print a nutrition label ---

async function main() {
  try {
    const result = await analyzeRecipe(
      "Avocado Toast",
      [
        "2 slices whole wheat bread",
        "1 medium avocado",
        "1 tbsp lemon juice",
        "1/4 tsp salt",
        "pinch of red pepper flakes",
      ],
      2
    );

    // Print each ingredient with its confidence
    console.log("Ingredients:");
    for (const ing of result.ingredients) {
      const cal = ing.nutrients.calories.toFixed(0);
      console.log(`  ${ing.parsed} - ${cal} cal (confidence: ${ing.confidence})`);
    }

    // Print per-serving totals
    console.log("\nPer serving:");
    const ps = result.per_serving;
    console.log(`  Calories: ${ps.calories.toFixed(0)}`);
    console.log(`  Protein:  ${ps.protein.toFixed(1)}g`);
    console.log(`  Fat:      ${ps.fat.toFixed(1)}g`);
    console.log(`  Carbs:    ${ps.carbs.toFixed(1)}g`);

    // Print labels
    console.log(`\nDiet labels: ${result.diet_labels.join(", ")}`);
    console.log(`Health labels: ${result.health_labels.join(", ")}`);

  } catch (error) {
    if (error.message.includes("401")) {
      console.error("Invalid API key. Set NUTRIENTAPI_KEY environment variable.");
    } else if (error.message.includes("429")) {
      console.error("Rate limited. Implement exponential backoff.");
    } else {
      console.error("Error:", error.message);
    }
    process.exit(1);
  }
}

main();

Ruby

Uses the standard library only (no gems required).

require "net/http"
require "json"
require "uri"

API_KEY = ENV.fetch("NUTRIENTAPI_KEY")
API_URL = URI("https://api.nutrientapi.com/v1/analyze")

def analyze_recipe(title:, ingredients:, servings: 1)
  http = Net::HTTP.new(API_URL.host, API_URL.port)
  http.use_ssl = true
  http.read_timeout = 30

  request = Net::HTTP::Post.new(API_URL.path)
  request["Content-Type"] = "application/json"
  request["Authorization"] = "Bearer #{API_KEY}"
  request.body = {
    title: title,
    ingredients: ingredients,
    servings: servings
  }.to_json

  response = http.request(request)

  case response
  when Net::HTTPSuccess
    JSON.parse(response.body)
  when Net::HTTPUnauthorized
    raise "Invalid API key. Check NUTRIENTAPI_KEY."
  when Net::HTTPUnprocessableEntity
    raise "Validation error: #{response.body}"
  when Net::HTTPTooManyRequests
    raise "Rate limited. Back off and retry."
  else
    raise "API error #{response.code}: #{response.body}"
  end
end

# --- Example usage ---

result = analyze_recipe(
  title: "Avocado Toast",
  ingredients: [
    "2 slices whole wheat bread",
    "1 medium avocado",
    "1 tbsp lemon juice",
    "1/4 tsp salt",
    "pinch of red pepper flakes"
  ],
  servings: 2
)

# Per-serving summary
ps = result["per_serving"]
puts "Per serving: #{ps["calories"].round} cal, " \
     "#{ps["protein"].round(1)}g protein, " \
     "#{ps["fat"].round(1)}g fat, " \
     "#{ps["carbs"].round(1)}g carbs"

# Labels
puts "Diet labels: #{result["diet_labels"].join(", ")}"
puts "Health labels: #{result["health_labels"].join(", ")}"

# Flag low-confidence matches
result["ingredients"].each do |ing|
  if ing["confidence"] < 0.8
    puts "Low confidence (#{ing["confidence"]}): #{ing["parsed"]}"
  end
end

Integration Tips

Cache responses. Unlike some nutrition APIs, NutrientAPI allows you to cache results without restrictions. Store nutrition data alongside your recipes in your database. Only call the API when ingredients change.
Use confidence scores. Every ingredient in the response includes a confidence field (0.0 to 1.0). Set a threshold for your app -- 0.8 is a good starting point. Flag or review results below your threshold rather than displaying them without qualification.
Handle rate limits. If you receive a 429 response, implement exponential backoff. Wait 1 second, then 2, then 4, up to a maximum. Do not retry immediately in a tight loop.

Common Patterns

  • Batch analysis: Send all ingredients for a recipe in a single request rather than one ingredient at a time. The API is designed for whole-recipe analysis.
  • Ingredient formatting: Include quantities and units in natural language. "2 cups diced chicken breast" works better than "chicken breast" because the API can compute accurate gram weights from the quantity.
  • Servings: Set the servings field to get automatic per-serving calculations in the response. You do not need to divide totals yourself.
  • Error responses: The API returns JSON error bodies with descriptive messages. Parse the response body on non-2xx status codes for actionable diagnostics.