Skip to content

Food Portion Size Calculator API: Scale Nutrition to Any Serving in One Call

Published June 15, 2026

A food portion size calculator API takes a food ID and a gram amount and returns calories, protein, carbohydrates, fat, fiber, and other macros for exactly that serving, no client-side math required. Instead of fetching per-100g data and multiplying by a fraction in every view, you call one endpoint and render the result.

This pattern is especially valuable for meal logging apps where users pick a food, enter their portion in grams, and expect the macro display to update instantly and accurately.

The Endpoint

GET /api/v1/public/calc/portion

Parameters:

ParameterTypeExampleNotes
food_idinteger12345From /search/foods or /foods/{id}
gramsfloat150Serving size in grams (0 < grams ≤ 5000)

Quick Start

First, find a food ID via search:

curl "https://api.calorieapi.com/api/v1/public/search/foods?q=chicken+breast&limit=1"

Then scale it to your serving:

curl "https://api.calorieapi.com/api/v1/public/calc/portion?food_id=12345&grams=200"

Response:

{
  "food_id": 12345,
  "food_name": "Chicken breast, raw",
  "requested_grams": 200,
  "nutrition": {
    "calories": 240.0,
    "protein_g": 44.0,
    "carbohydrates_g": 0.0,
    "fat_g": 5.0,
    "fiber_g": 0.0,
    "sugars_g": 0.0,
    "saturated_fat_g": 1.4,
    "sodium_g": 0.14
  }
}

All fields are already scaled to the requested gram amount. calories is the energy for exactly 200 g of chicken breast — not per 100 g.

Why Offload the Scaling Math

Doing (grams / 100) × nutrient_per_100g in client code is trivial but error-prone at scale:

  • Different platforms round floating-point differently
  • Each client must implement and test the same formula
  • Nutrient fields may be null — division by zero edge cases accumulate
  • A backend formula update requires releasing all clients simultaneously

Centralising this in the API keeps all clients consistent and lets you improve accuracy without a client release.

Building a Portion Picker in React

import { useState, useCallback } from 'react'

function PortionPicker({ food }) {
  const [grams, setGrams] = useState(100)
  const [nutrition, setNutrition] = useState(null)

  const fetchNutrition = useCallback(async (amount) => {
    const res = await fetch(
      `https://api.calorieapi.com/api/v1/public/calc/portion?food_id=${food.id}&grams=${amount}`
    )
    if (!res.ok) return
    const data = await res.json()
    setNutrition(data.nutrition)
  }, [food.id])

  return (
    <div>
      <label>
        Grams
        <input
          type="number" value={grams} min={1}
          onChange={e => { setGrams(e.target.value); fetchNutrition(e.target.value) }}
        />
      </label>
      {nutrition && (
        <dl>
          <dt>Calories</dt><dd>{nutrition.calories} kcal</dd>
          <dt>Protein</dt><dd>{nutrition.protein_g} g</dd>
          <dt>Carbs</dt><dd>{nutrition.carbohydrates_g} g</dd>
          <dt>Fat</dt><dd>{nutrition.fat_g} g</dd>
        </dl>
      )}
    </div>
  )
}

Debounce the onChange handler by 200–300 ms to avoid a request on every keystroke.

Common Serving Presets

Most users pick from a fixed list rather than typing a gram value. Map common serving descriptions to grams before calling the endpoint:

const SERVING_PRESETS = {
  '1 cup':      240,
  '1/2 cup':    120,
  '1 tbsp':      15,
  '1 tsp':        5,
  '100g':       100,
  '1 oz':        28,
  '1 medium':   150,
  '1 large':    200,
}

const grams = SERVING_PRESETS[selectedServing] ?? parseFloat(customGrams)

Pass the resolved grams value to the portion endpoint.

Null Fields

Some foods lack complete nutrient coverage. The nutrition object omits fields with no data (they appear as null). Handle this gracefully:

const display = (value, unit) =>
  value != null ? `${value} ${unit}` : '—'

console.log(display(nutrition.fiber_g, 'g'))  // "3.2 g" or "—"

Caching Strategy

The portion endpoint is deterministic: the same food_id + grams always returns the same result (until the underlying food record is updated). You can safely cache responses in memory or localStorage:

const cache = new Map()
const key = `${foodId}:${grams}`

if (!cache.has(key)) {
  const result = await fetchPortion(foodId, grams)
  cache.set(key, result)
}
return cache.get(key)

For high-traffic apps, set a 24-hour TTL to pick up any food data corrections.

Try it in the playground | Get your free API key

Frequently Asked Questions

What does a food portion size calculator API do?

It takes a food ID and a gram amount and returns exact calories, protein, carbohydrates, fat, and other macros scaled to that specific serving — eliminating client-side nutrient scaling math.

How do I get a food ID to use with the portion endpoint?

Search for the food using GET /search/foods and use the id field from the result. Store the id after the first lookup to skip repeat searches.

What units does the portion endpoint accept?

The endpoint accepts grams only. For recipes using cups, tablespoons, or ounces, convert to grams using a unit conversion table before calling the endpoint.

Are null nutrition fields safe to use?

Yes. Some foods lack complete nutrient coverage. Treat null fields as unknown rather than zero, and show a dash or 'N/A' in the UI rather than displaying zero.

Can I cache portion API responses?

Yes. Responses are deterministic for the same food_id and grams. Cache with a 24-hour TTL to stay current with food data updates while reducing API calls.

← Back to all articles

Start building with the Calorie API

Get a free API key and access 4M+ foods with search, barcode lookup, and full macro data.