Usage examples

Short, runnable recipes for the most common workflows on the v3 namespaced surface (fs.foods, fs.diary, fs.recipes …). Methods return typed Pydantic models, so prefer attribute access (food.food_name) over dict lookups.

All numeric nutrition fields (calories, protein, fat …) are decimal.Decimal to preserve API precision — convert with float() when you need to do arithmetic with regular numbers.

Initialize a public client (OAuth2)

For public-data endpoints (food search, food.get, recipe search, …) the client-credentials flow is enough. No user login required.

from fatsecret import Fatsecret

fs = Fatsecret(
    consumer_key="YOUR_KEY",
    consumer_secret="YOUR_SECRET",
    auth="oauth2",
    scopes=["basic"],
)

# Ready for any non-delegated call.
foods = fs.foods.search_v5(search_expression="banana", max_results=3)

Initialize an authenticated client (OAuth1)

For user-scoped endpoints (food diary, weight log, saved meals, …) use OAuth1 with a previously-obtained (token, secret) pair you have persisted for the user.

from fatsecret import Fatsecret

# token + secret were saved at the end of the OAuth1 dance
# (see the "OAuth Examples" page for how to obtain them).
access_token = ("USER_TOKEN", "USER_TOKEN_SECRET")

fs = Fatsecret(
    consumer_key="YOUR_KEY",
    consumer_secret="YOUR_SECRET",
    session_token=access_token,
    auth="oauth1",
)

# User-scoped calls now work, e.g.:
profile = fs.profile.get_v1()

Search foods

foods.search_v5 returns list[Food]. Iterate and read typed attributes directly.

from fatsecret import Fatsecret

fs = Fatsecret("KEY", "SECRET", auth="oauth2", scopes=["basic"])

results = fs.foods.search_v5(search_expression="banana", max_results=5)

for food in results:
    print(food.food_id, food.food_name, food.brand_name, food.food_type)
# 38821 Banana None Generic
# ...

Get nutrition for a specific food

foods.get_v5 returns a single Food whose servings contain per-serving nutrition. Each Serving carries Decimal macros.

from fatsecret import Fatsecret

fs = Fatsecret("KEY", "SECRET", auth="oauth2", scopes=["basic"])

food = fs.foods.get_v5(food_id=38821)

print(food.food_name)
for serving in food.servings.serving:
    print(
        serving.serving_description,
        f"{float(serving.calories):.0f} kcal",
        f"P {serving.protein}g  C {serving.carbohydrate}g  F {serving.fat}g",
    )

Search and log a meal

Pick the first match for a query, then write a food_entry against the user’s diary. Requires an authenticated (OAuth1) client.

from datetime import date

from fatsecret import Fatsecret

fs = Fatsecret(
    "KEY", "SECRET",
    session_token=("USER_TOKEN", "USER_TOKEN_SECRET"),
    auth="oauth1",
)

# 1. Find the food.
matches = fs.foods.search_v5(search_expression="banana", max_results=1)
food = fs.foods.get_v5(food_id=matches[0].food_id)
serving = food.servings.serving[0]

# 2. Log one serving as breakfast for today.
entries = fs.diary.entry_create_v1(
    food_id=food.food_id,
    food_entry_name=food.food_name,
    serving_id=serving.serving_id,
    number_of_units=1.0,
    meal="Breakfast",
    date=date.today(),
)

print("Logged entry id:", entries[0].food_entry_id)

Get the day’s food entries

diary.entries_get_v2 returns list[FoodEntry] for a given day. The date parameter accepts a date/datetime/Unix timestamp — the SDK converts it to FatSecret’s day-since-epoch encoding for you.

from datetime import date

from fatsecret import Fatsecret

fs = Fatsecret(
    "KEY", "SECRET",
    session_token=("USER_TOKEN", "USER_TOKEN_SECRET"),
    auth="oauth1",
)

entries = fs.diary.entries_get_v2(date=date.today())

total_kcal = sum(float(e.calories or 0) for e in entries)
for e in entries:
    print(f"{e.meal:10s} {e.food_entry_name:30s} {e.calories} kcal")
print(f"TOTAL: {total_kcal:.0f} kcal across {len(entries)} entries")

Recipe lookup with ingredients

recipes.search_v3 returns list[RecipesRecipe]. The list view is sparse — call recipes.get_v2 for full ingredients and nutrition.

from fatsecret import Fatsecret

fs = Fatsecret("KEY", "SECRET", auth="oauth2", scopes=["basic"])

hits = fs.recipes.search_v3(
    search_expression="tomato soup",
    max_results=3,
)
for r in hits:
    print(r.recipe_id, r.recipe_name)

# Drill into the first recipe for ingredients + macros.
recipe = fs.recipes.get_v2(recipe_id=hits[0].recipe_id)
print(recipe.recipe_name)
for ingredient in recipe.recipe_ingredients.ingredient:
    print(" -", ingredient)
print("kcal/serving:", recipe.recipe_nutrition.calories)

Backwards-compat dict access (.to_dict())

Callers migrating from v2 (which returned plain dicts) can drop into the legacy shape via .to_dict() on any model. Useful as a short-term shim while you port code to typed attribute access.

from pprint import pprint

from fatsecret import Fatsecret

fs = Fatsecret("KEY", "SECRET", auth="oauth2", scopes=["basic"])

food = fs.foods.get_v5(food_id=38821)

# Typed (preferred):
print(food.food_name, food.food_id)

# Dict (v2-compatible):
pprint(food.to_dict())
# {'food_id': '38821', 'food_name': 'Banana', 'servings': {...}, ...}