JavaScript (browser)
Use a read-only key, or proxy through your own backend so no key ships at all.
const url = new URL('https://api.getdietly.com/search');
url.search = new URLSearchParams({ q: 'greek yogurt', limit: '5' });
const response = await fetch(url, {
headers: { Authorization: 'Bearer YOUR_READ_ONLY_KEY' }
});
if (!response.ok) throw new Error(`DietlyAPI ${response.status}`);
const foods = await response.json(); // bare array, [] on no match
console.log(foods[0]?.name, foods[0]?.calories_kcal, 'kcal/100g');
Node.js
Node 18+ has fetch built in. Read the rate-limit headers to pace batch jobs.
const response = await fetch(
'https://api.getdietly.com/search?q=' + encodeURIComponent('greek yogurt') + '&limit=5',
{ headers: { Authorization: `Bearer ${process.env.DIETLY_API_KEY}` } }
);
if (response.status === 429) {
const wait = Number(response.headers.get('Retry-After') || 1);
await new Promise(r => setTimeout(r, wait * 1000)); // then retry
}
const foods = await response.json();
// pace long-running imports before you get throttled:
const remaining = Number(response.headers.get('X-RateLimit-Remaining'));
if (remaining < 5) {
const reset = Number(response.headers.get('X-RateLimit-Reset') || 60);
await new Promise(r => setTimeout(r, reset * 1000));
}
Next.js
A route handler keeps the key server-side; your React components call /api/food-search instead of DietlyAPI directly.
// app/api/food-search/route.js
export async function GET(request) {
const q = new URL(request.url).searchParams.get('q') ?? '';
if (q.length < 2) return Response.json([]);
const upstream = await fetch(
`https://api.getdietly.com/search?q=${encodeURIComponent(q)}&limit=8`,
{
headers: { Authorization: `Bearer ${process.env.DIETLY_API_KEY}` },
next: { revalidate: 3600 }, // cache identical searches for an hour
}
);
if (!upstream.ok) return Response.json([], { status: upstream.status });
return Response.json(await upstream.json());
}
Python
import os
import requests
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['DIETLY_API_KEY']}"
response = session.get(
"https://api.getdietly.com/search",
params={"q": "greek yogurt", "limit": 5},
timeout=10,
)
response.raise_for_status()
foods = response.json() # list[dict], not {'results': [...]}
for food in foods:
print(food["name"], food.get("calories_kcal"), "kcal/100g")
React Native / Expo
Mobile bundles can be unpacked — ship a read-only key with a rate cap, never your full-access key. Images work without any key via image_thumb_url.
const searchFoods = async (query) => {
const response = await fetch(
`https://api.getdietly.com/search?q=${encodeURIComponent(query)}&limit=10`,
{ headers: { Authorization: 'Bearer YOUR_READ_ONLY_KEY' } }
);
if (!response.ok) return [];
return response.json();
};
// barcode scan miss (404) is a normal state, not an error:
const scanBarcode = async (ean) => {
const response = await fetch(`https://api.getdietly.com/barcode/${ean}`, {
headers: { Authorization: 'Bearer YOUR_READ_ONLY_KEY' }
});
return response.status === 404 ? null : response.json();
};
Flutter
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<List<dynamic>> searchFoods(String query) async {
final uri = Uri.https('api.getdietly.com', '/search', {
'q': query,
'limit': '10',
});
final response = await http.get(uri, headers: {
'Authorization': 'Bearer YOUR_READ_ONLY_KEY',
});
if (response.statusCode != 200) return [];
return jsonDecode(response.body) as List<dynamic>; // bare array
}
PHP
$query = http_build_query(['q' => 'greek yogurt', 'limit' => 5]);
$context = stream_context_create(['http' => [
'header' => 'Authorization: Bearer ' . getenv('DIETLY_API_KEY'),
'timeout' => 10,
]]);
$body = file_get_contents("https://api.getdietly.com/search?$query", false, $context);
$foods = json_decode($body, true); // plain array, [] on no match
echo $foods[0]['name'] ?? 'No match';
AI assistants (LLM tool calling)
Give a model a search_foods tool and it can answer nutrition questions with real database rows instead of guesses. The definition below works with the Claude and OpenAI tool-calling formats alike.
{
"name": "search_foods",
"description": "Search the DietlyAPI food database (4M+ foods) by name or brand. Returns foods with calories, protein, fat, carbs and more per 100 g. Use for any question about the nutrition of a specific food or product.",
"input_schema": {
"type": "object",
"properties": {
"q": { "type": "string", "description": "Food or brand to search, e.g. 'greek yogurt'" },
"limit": { "type": "integer", "description": "Max results, 1-25", "default": 5 }
},
"required": ["q"]
}
}
When the model calls the tool, run the request server-side and return the JSON to the model:
async function runSearchFoods({ q, limit = 5 }) {
const response = await fetch(
`https://api.getdietly.com/search?q=${encodeURIComponent(q)}&limit=${limit}`,
{ headers: { Authorization: `Bearer ${process.env.DIETLY_API_KEY}` } }
);
return response.ok ? response.json() : [];
}
Next steps
The integration guide covers response shapes, nulls, retries, nutrition units and the launch checklist. The dashboard has a live playground and per-key usage. Where Open Food Facts data is displayed, include a visible credit such as Food data from Open Food Facts (ODbL) via DietlyAPI — details in the API Terms.