API di ricerca alimenti
Ricerca full-text su 6,1 milioni di prodotti alimentari per nome, marca o categoria — ordinata per rilevanza, paginata e veloce. Cerca in qualsiasi lingua in cui sia stampata l'etichetta (cirillico incluso) e passa lang=en|fr|es|de|it|bg per nomi, categorie e allergeni localizzati. Una sola richiesta GET restituisce JSON pulito, pronto da mostrare nella tua app.
curl -H "X-API-Key: food_•••" \
"https://foodbase.dev/v1/foods/search?q=banana&limit=20"
{
"data": [
{
"id": "034becf0-9aa7-c748-41aa-b71dd4df2bae",
"name_default": "Bananes",
"name_localized": "Bananas",
"brand": "Bio Village, Marque Repère",
"barcode": "3564707141710",
"category": "...,Fruits,Fruits tropicaux,Bananes",
"nutriscore": "a"
}
],
"total": 1000,
"limit": 20,
"offset": 0
} Preferisci cliccare? Prova l'esploratore di prodotti o l'area di prova foto.
Cosa ottieni
id
ID stabile dell'alimento — usalo con gli altri endpoint.
name_default
Nome del prodotto nella sua lingua principale.
name_localized / category_localized
Traduzioni nella lang richiesta (en, fr, es, de, it, bg) quando disponibili — altrimenti il testo originale.
brand
Marca / produttore, quando noto.
barcode
Codice a barre EAN-13 / UPC, quando disponibile.
category
Categoria alimentare di primo livello.
total / limit / offset
Metadati di paginazione per l'intero insieme dei risultati.
Incluso nel piano gratuito — 100 richieste/giorno, nessuna carta di credito richiesta. Vedi i piani →
Esempi di codice
La stessa richiesta in curl, JavaScript e Python. Sostituisci YOUR_API_KEY con una chiave della tua dashboard.
curl "https://foodbase.dev/v1/foods/search?q=banana&limit=20" \
-H "X-API-Key: YOUR_API_KEY"
const res = await fetch("https://foodbase.dev/v1/foods/search?q=banana&limit=20", {
headers: { "X-API-Key": "YOUR_API_KEY" },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
import requests
res = requests.get(
"https://foodbase.dev/v1/foods/search?q=banana&limit=20",
headers={"X-API-Key": "YOUR_API_KEY"},
timeout=30,
)
res.raise_for_status()
data = res.json()
Come funziona
Cosa fa una singola richiesta di ricerca
Una ricerca è una singola GET con il testo in q. Le parole vengono confrontate insieme con il nome del prodotto e con la marca, quindi q=olympus milk trova prodotti il cui nome non dice mai Olympus, e l'ultima parola è trattata come prefisso, così milk olym trova già qualcosa mentre l'utente sta ancora scrivendo. Devono corrispondere tutte le parole; non esiste l'OR. q deve essere lungo da 1 a 200 caratteri; una q mancante o vuota viene rifiutata prima che parta qualsiasi ricerca, quindi gestisci tu il caso della casella di ricerca vuota.
I prodotti che si chiamano esattamente come hai digitato vengono per primi, quindi banana elenca le banane prima degli yogurt alla banana e greek yogurt elenca gli yogurt greci naturali. Dopo di loro i risultati sono ordinati per rilevanza e, a parità di corrispondenza, viene prima il prodotto più popolare. Una query di marca come pringles salta il passaggio del nome esatto e resta in ordine di popolarità; aggiungere una seconda parola (una marca, un gusto) è il modo più rapido per far salire un prodotto specifico.
I nomi di categoria sono un ripiego, non parte della corrispondenza principale: solo quando la ricerca su nome e marca non trova nulla l'API cerca i prodotti la cui categoria contiene le parole, nella lingua in cui la categoria è memorizzata. È questo che fa restituire una lista (ordinata per popolarità) a una query come Seeds & Related Snacks o Fruits tropicaux, invece di un array vuoto.
- L'ordine non è né alfabetico né per id. Non riordinare l'array data lato client.
- Se l'input è un GTIN di sole cifre, invialo alla Barcode Lookup API: risolve le varianti con zeri di riempimento (0000080042556 trova 80042556), cosa che una ricerca testuale non fa.
Leggere una riga di risultato
Ogni elemento di data è un FoodListItem, una forma più leggera del record completo: id, barcode, source, name_default, brand, category, image_url, nutriscore e nova_group, più name_localized (sempre presente) e category_localized quando passi una lang diversa dall'inglese. Qui non ci sono nutrienti; l'elenco è fatto per mostrare righe, non per fare calcoli.
Diversi campi possono essere null, e l'esempio lo mostra. La caramella Roshen “Banana land” (4f995c13-c0df-bfcc-b6ec-449d312def75) ha image_url null e nova_group null; anche brand e barcode possono essere null. I valori di nutriscore diversi da a–e, come la “n” e la “u” dell'esempio, significano che non è stato calcolato alcun voto: mostrali come “non classificato” invece della lettera grezza.
category è il percorso completo delle categorie di Open Food Facts, separato da virgole dal generale allo specifico (“...,Fruits tropicaux,Bananes” per le banane Bio Village). Mostra l'ultimo segmento come etichetta, oppure il primo per un raggruppamento grossolano, e rimuovi prefissi di lingua come pt: prima di visualizzarlo. image_url è una foto di un contributore su images.openfoodfacts.org, quindi prevedi un segnaposto per il caso null.
Paginazione, total e id stabili
limit va da 1 a 100 (predefinito 20) e offset da 0 a 10000. total è un conteggio limitato: l'API smette di contare a 1.000 corrispondenze, quindi il total di 1000 dell'esempio per q=banana con limit=3 significa almeno 1.000. Mostralo come “1.000+” e non calcolare un numero di ultima pagina a partire da esso.
Pagina sommando limit a offset finché data non restituisce meno di limit elementi. Poiché offset arriva al massimo a 10000, una query con più corrispondenze di così richiede una q più stretta, non una pagina più profonda.
- Gli id sono stabili tra le reimportazioni di FoodBase: salva l'id di una riga di ricerca e risolvilo più tardi con la Food Database API senza cercare di nuovo.
- Il ranking è calcolato a ogni richiesta e la popolarità può cambiare, quindi un offset non è un cursore duraturo. Conserva gli id, non le posizioni di pagina.
Cercare in un'altra lingua
lang è en per impostazione predefinita. Ogni lingua cerca nella voce di quella lingua dell'array dei nomi del prodotto, dove un volontario o la traduzione IA di FoodBase l'ha fornita, e ripiega su name_default, il nome così com'è stampato sull'etichetta, per i prodotti che non hanno quella voce; la marca fa sempre parte della corrispondenza. Quindi lang=bg raggiunge ogni prodotto ma preferisce i nomi bulgari dove esistono, e un'etichetta in cirillico si trova con qualsiasi lang.
La lang che passi plasma anche l'output. name_localized contiene il nome tradotto: l'esempio, richiesto con lang=en, trasforma “Puré de plátano y fresa” in “Banana and Strawberry Puree” e ripiega su name_default quando non c'è nulla da tradurre, come mostra “Banana land”. Mostra name_localized quando non è null e name_default altrimenti. category_localized non è un campo obbligatorio e non compare nell'esempio, quindi leggilo in modo difensivo.
Autocompletamento e passaggio ai record completi
La ricerca è l'endpoint giusto per una casella con suggerimenti in tempo reale. Applica il debounce ai tasti, richiedi limit=8 o 10 e annulla la richiesta in corso quando l'utente digita di nuovo, così una risposta lenta precedente non può sovrascriverne una più recente. Ogni tasto che arriva all'API è una richiesta contro la tua quota giornaliera, quindi il debounce è tanto un controllo dei costi quanto un dettaglio di UX.
Quando l'utente sceglie una riga, chiama la Food Database API con l'id per il record completo, oppure la Nutrition API quando ti serve solo la tabella dei nutrienti per 100 g. Una ricerca più una richiesta di dettaglio costa meno che recuperare i record completi per ogni suggerimento.
La risposta di ricerca catturata non ha alcun header Cache-Control, a differenza dei record alimentari, che sono memorizzabili in cache per 300 secondi. Metti in cache i risultati di ricerca da solo, con chiave sull'esatta combinazione di q, lang, limit e offset; in una casella con suggerimenti gli stessi brevi prefissi ricorrono continuamente. X-RateLimit-Second-Remaining mostra quanto burst resta e, su un 429, l'header Retry-After indica quanti secondi attendere.
Cosa puoi costruire
Selettori di alimenti e autocompletamento
Dai vita alla casella di ricerca di un contacalorie o di un'app di ricette — risultati in tempo reale su 6,1 mln di prodotti.
Arricchimento del catalogo
Associa i tuoi SKU ai record alimentari canonici per nome o marca.
Feed di scoperta
Sfoglia per categoria o parola chiave per creare elenchi di alimenti curati.
Limiti per piano
| Free | 100 richieste/giorno condivise tra le chiavi dell'account; 1 richiesta/s per chiave, burst 5. Il limite di 25/giorno per il dettaglio dei nutrienti non si applica alla ricerca. |
|---|---|
| Starter | 5.000 richieste/giorno; 5 richieste/s per chiave, burst 25. |
| Pro | 25.000 richieste/giorno; 20 richieste/s per chiave, burst 100. |
| Enterprise | 100.000 richieste/giorno; 50 richieste/s per chiave, burst 250. |
Ogni risposta include gli header X-RateLimit-* con il budget residuo; ogni 429 include Retry-After . Confronta i piani →
Errori e come gestirli
401 — L'header X-API-Key manca, è malformato o appartiene a una chiave revocata.
Controlla il nome dell'header e la chiave nella tua dashboard. Non riprovare finché non è risolto.
422 — q manca o è vuota, supera i 200 caratteri, limit è fuori dall'intervallo 1–100, offset è fuori dall'intervallo 0–10000, oppure lang non è una tra en, fr, es, de, it, bg.
Leggi l'array details nel corpo Validation Error per capire quale parametro non va e correggi la richiesta lato client. Non riprovare mai un 422 invariato.
429 — Il burst al secondo della chiave è esaurito oppure la quota giornaliera dell'account è finita.
Attendi il numero di secondi indicato in Retry-After e riprova una volta. In un flusso di autocompletamento, scarta il tasto ormai superato invece di metterlo in coda.
Confronto con altre API
Un motore di ricerca generico o il catalogo di un e-commerce indicizza testo; la ricerca di FoodBase indicizza prodotti alimentari, quindi una corrispondenza torna con codice a barre, percorso di categoria, Nutri-Score e gruppo NOVA già allegati, e con un id che si risolve in una tabella di nutrienti con una sola richiesta in più. Il compromesso è l'ambito: corrisponde a nomi di prodotto e marche, con i nomi di categoria solo come ripiego, e non a ogni campo del record; inoltre una lang non inglese cerca nei nomi localizzati dove esistono e nei nomi d'etichetta altrove, invece di tradurre la tua query. Non c'è nessuna libreria client da installare e nessun indice da costruire da parte tua, solo una GET e un oggetto JSON. Se stai confrontando fornitori di dati alimentari, /compare/food-database-apis mostra cosa copre ciascuno.
Domande frequenti
Perché total torna esattamente come 1000? +
Il conteggio è limitato. Il conteggio si ferma a 1.000 corrispondenze, quindi 1000 significa almeno quel numero. Mostralo come “1.000+” e pagina con offset finché data non restituisce meno di limit righe, invece di dividere total per limit.
Cosa restituisce l'API quando nulla corrisponde? +
Un 200 con un array data vuoto, non un 404. Trattalo come il tuo stato “nessun risultato”. Poiché ogni parola di q deve corrispondere, togliere la parola meno specifica o una soggetta a refusi è di solito il rimedio, prima di mostrare il vuoto.
Posso cercare solo per marca o solo per categoria? +
Per marca sì: la marca fa parte di ciò con cui viene confrontata ogni parola di q, quindi q=Hacendado elenca i prodotti di quella marca e aggiungere una parola di prodotto restringe l'elenco. I nomi di categoria vengono provati solo quando la ricerca su nome e marca non restituisce nulla, quindi q=Fruits tropicaux restituisce i prodotti classificati in quella categoria, ordinati per popolarità e non per rilevanza.
Un risultato di ricerca include i nutrienti? +
No. Le righe di ricerca hanno la forma più leggera FoodListItem, senza campi nutrizionali. Passa l'id della riga alla Nutrition API alla selezione e non per ogni suggerimento, perché il piano Free consente 25 dettagli nutrizionali al giorno.
Quale lang dovrebbe passare un'app bulgara? +
lang=bg cerca nei nomi localizzati in bulgaro e restituisce name_localized in bulgaro dove esiste una traduzione. Le etichette inserite in cirillico come nome predefinito si trovano con lang=en, perché en cerca nel nome predefinito indipendentemente dalla scrittura. Interroga prima bg e ripiega su en in caso di risultato vuoto.
Il ranking è lo stesso del sito web di FoodBase? +
Sì. L'esplora prodotti su /products e le pagine di categoria su /categories/ usano lo stesso endpoint, quindi puoi provare una query lì e aspettarti lo stesso ordine nella tua app a parità di q e lang. La ricerca non usa crediti IA; ogni chiamata è una richiesta contro la quota giornaliera.
Scopri altri endpoint
API di ricerca per codici a barre
Scansiona o digita un codice a barre, ottieni il prodotto. Risolvi qualsiasi codice EAN-13 o UPC in un record alimentare — marca, categoria, Nutri-Score e riepilogo nutrizionale — con una sola richiesta. Pensata per le app basate su scanner.
Scopri di più →API del database alimentare
Un'unica fonte per 6,1 milioni di alimenti. Recupera un record di prodotto completo tramite ID — nome, marca, ingredienti, allergeni, Nutri-Score, gruppo NOVA, immagini e altro.
Scopri di più →API nutrizionali
Vai oltre i macronutrienti principali. Ottieni il dettaglio di oltre 40 nutrienti per prodotto — energia, proteine, carboidrati, grassi, zuccheri, fibre, sodio, vitamine e minerali — tutti per 100 g, per qualsiasi alimento tramite ID.
Scopri di più →Inizia subito con API di ricerca alimenti
Gratis per iniziare. Nessuna carta di credito richiesta.
Ottieni la chiave API Vai alla dashboard