API di ricerca multipla di alimenti
Ottieni fino a 100 alimenti in un'unica richiesta. Invia un array di ID o di codici a barre e ricevi le schede complete, più l'elenco di ciò che non è stato trovato: ideale per riempire un piano alimentare, un carrello, il diario alimentare di una giornata o un catalogo di prodotti scansionati senza cento andate e ritorno.
curl -X POST -H "X-API-Key: food_•••" \
-H "Content-Type: application/json" \
-d '{"ids":["62ea12b8...","2fc13a3b..."]}' \
"https://foodbase.dev/v1/foods/bulk"
{
"data": [
{ "id": "62ea12b8...", "name_default": "Original Taste", "brand": "Coca-Cola" },
{ "id": "2fc13a3b...", "name_default": "Nutella", "brand": "Ferrero" }
],
"not_found": []
} Preferisci cliccare? Prova l'esploratore di prodotti o l'area di prova foto.
Cosa ottieni
ids[]
Da 1 a 100 ID di alimenti nel corpo della richiesta, oppure:
barcodes[]
Da 1 a 100 codici a barre (GTIN-8/12/13/14), ognuno risolto come nell'API di ricerca per codice a barre, varianti con zeri iniziali comprese.
data[]
Schede complete nell'ordine richiesto; le ricerche per codice a barre aggiungono requested_barcode (il codice inviato).
not_found[]
Gli ID o i codici a barre senza prodotto, nessun errore per il lotto.
?lang=
Facoltativo: en/fr/es/de/it/bg, come nelle ricerche di una singola scheda.
Disponibile dal piano Starter in su. 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/bulk" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids":["62ea12b8-b260-c288-5c38-3a4906f5d6dd","2fc13a3b-1913-5ab6-d2c7-8c09b56f93bb"]}'
const res = await fetch("https://foodbase.dev/v1/foods/bulk", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
"ids": [
"62ea12b8-b260-c288-5c38-3a4906f5d6dd",
"2fc13a3b-1913-5ab6-d2c7-8c09b56f93bb"
]
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
import requests
res = requests.post(
"https://foodbase.dev/v1/foods/bulk",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"ids": [
"62ea12b8-b260-c288-5c38-3a4906f5d6dd",
"2fc13a3b-1913-5ab6-d2c7-8c09b56f93bb"
]
},
timeout=30,
)
res.raise_for_status()
data = res.json()
Come funziona
La richiesta, passo per passo
POST /v1/foods/bulk con Content-Type: application/json, la tua intestazione X-API-Key e un corpo della forma {"ids": [...]} o {"barcodes": [...]}: esattamente uno dei due, da 1 a 100 voci. Gli ids sono stringhe UUID (quelli degli esempi di codice qui sopra sono schede reali con cui fare prove); i codici a barre vengono risolti esattamente come con GET /v1/foods/barcode/{code}, quindi un EAN-13 trova anche un prodotto salvato nella sua forma UPC-12 o GTIN-14, e il campo barcode della scheda mostra la forma salvata accanto a requested_barcode.
La validazione avviene prima di toccare il database ed è tutto o niente. Un codice a barre dentro ids, entrambi i campi o nessuno, un array vuoto o 101 voci rifiutano l'intero lotto con 422 {"error": "Validation Error", "details": [{"field": "ids.3", "message": ...}]}. Un ?lang= facoltativo (en, fr, es, de, it, bg) localizza le etichette di categoria e allergeni come nelle ricerche di una singola scheda; nomi e ingredienti in altre lingue si trovano negli array name e ingredients.
Leggere la risposta
data è un array di oggetti FoodItem costruiti dallo stesso formattatore della Food Database API, quindi un parser scritto per il singolo record funziona senza modifiche, da id, barcode e source fino a categories_tags, image_url e allergens. I dati mancanti nella fonte sono null, mai una chiave assente.
nutrition_summary contiene energy_kcal, proteins_g, carbs_g, fat_g, sugars_g e fiber_g per 100 g. È null per intero solo quando il prodotto non ha alcuna riga di nutrienti; una riga a cui manca un valore mostra null solo per quella chiave. Testi d'etichetta come quantity e serving_size_raw arrivano esattamente come li hanno digitati i contributori, quindi analizzali in modo difensivo.
Voci mancanti, duplicati e deriva
La risposta può essere più corta della richiesta: non c'è un 404 per voce, ma ogni id o codice a barre senza prodotto è elencato in not_found, nell'ordine della richiesta, quindi non devi mai confrontarli tu. Un id o un codice a barre inviato due volte torna come una sola scheda: elimina i duplicati prima dell'invio, così ognuno dei 100 posti conta.
Gli id sono deterministici, derivati dalla fonte e dal suo identificativo di prodotto, quindi un prodotto mantiene il suo id tra le reimportazioni. Se un id salvato smette di risolversi, il prodotto non è più nel catalogo con quell'identità: segna la riga come obsoleta e risolvila di nuovo con la Barcode Lookup API o la Food Search API invece di eliminarla.
Quota e calcolo dei limiti
Una chiamata bulk è una richiesta contro la quota giornaliera e un token dal bucket al secondo, qualunque sia il numero di id. L'ordine del middleware è autenticazione, limite al secondo, controllo del piano, poi quota giornaliera, quindi un 401, un 429 per limite di frequenza o il 403 per Starter non consumano mai una richiesta giornaliera. Un 422 sì, perché la convalida avviene dopo il conteggio della quota; controlla gli UUID lato client.
Leggi gli header a ogni 200: X-RateLimit-Second-Limit, X-RateLimit-Burst-Capacity e X-RateLimit-Second-Remaining per il bucket per chiave, X-RateLimit-Account-Limit e X-RateLimit-Account-Remaining per l'aggregato al secondo su tutte le chiavi dell'account, e X-RateLimit-Daily-Limit, X-RateLimit-Daily-Remaining e X-RateLimit-Daily-Reset (sugli account normali) per il budget giornaliero condiviso e il suo reset a mezzanotte UTC. La POST non porta alcun header Cache-Control, quindi nulla viene messo in cache dall'edge per te: conserva ciò che recuperi.
Sincronizzare un catalogo ogni notte
Per l'assortimento di un rivenditore, invia direttamente i codici a barre, 100 per chiamata, oppure salva l'id restituito accanto al tuo SKU e sincronizza poi per id. In entrambi i casi il job notturno non cerca mai: legge i codici salvati, elimina i duplicati, li divide in gruppi da 100, invia ogni gruppo qui e salva un checkpoint dopo ogni gruppo completato, così un catalogo più grande del budget di una notte riprende da dove si era fermato. Confronta updated_at con la tua copia per sapere cosa è cambiato.
Regola il ritmo in base agli header invece che con una pausa fissa, e tieni d'occhio X-RateLimit-Daily-Remaining affinché la sincronizzazione non affami il traffico diurno sullo stesso account. Quando una vista richiede la tabella di oltre 40 nutrienti, chiama la Nutrition API per quell'id su richiesta; accetta un id per richiesta e conta anch'essa come richiesta.
- Deduplica gli id, dividi a blocchi di 100, registra un checkpoint per blocco.
- Segna come obsoleto tutto ciò che è in not_found; ricontrollalo più tardi.
- Recupera /nutrients in modo pigro, per prodotto, non nella sincronizzazione.
Cosa puoi costruire
Piani alimentari e diari alimentari
Risolvi ogni voce del piano di una giornata con una sola chiamata.
Idratazione del carrello
Trasforma un elenco di ID di alimenti salvati in record completi in modo efficiente.
Job di sincronizzazione
Aggiorna molti alimenti in cache a lotti, con una pianificazione.
Limiti per piano
| Free | Non disponibile: 403 con required_plan starter (non conta nelle 100 richieste/giorno) |
|---|---|
| Starter | 5.000 richieste/giorno, 5/s costanti, burst 25; fino a 100 ID o codici a barre per richiesta |
| Pro | 25.000 richieste/giorno, 20/s costanti, burst 100; fino a 100 ID o codici a barre per richiesta |
| Enterprise | 100.000 richieste/giorno, 50/s costanti, burst 250; fino a 100 ID o codici a barre per richiesta |
Ogni risposta include gli header X-RateLimit-* con il budget residuo; ogni 429 include Retry-After . Confronta i piani →
Errori e come gestirli
403 — Account Free; il corpo ha error Plan upgrade required, required_plan starter, current_plan free e un upgrade_url
Passa a un piano superiore all'upgrade_url, oppure usa GET /v1/foods/{id} su Free
422 — Nessuno o entrambi i campi ids e barcodes; un array vuoto o con più di 100 voci; un non-UUID in ids o un codice a barre vuoto; details[] indica la posizione non valida
Valida ed elimina i duplicati lato client; invia i codici a barre in barcodes[], non in ids[]
429 — Bucket per chiave o per account vuoto, oppure X-RateLimit-Daily-Remaining è arrivato a 0 (corpo: Daily quota exceeded)
Attendi Retry-After secondi; nel caso della quota giornaliera è il tempo fino a mezzanotte UTC
401 — Header X-API-Key mancante, oppure la chiave non è valida o è stata revocata
Controlla il nome dell'header e la chiave nella dashboard
503 — L'archivio di quota o limiti di frequenza non è raggiungibile; l'API si blocca per sicurezza
Riprova con backoff; la richiesta non è stata conteggiata
Confronto con altre API
Rispetto alla GET sul singolo record, il guadagno sta in round-trip e quota: 100 record con una richiesta invece di 100 richieste. La GET vince quando molti client leggono lo stesso prodotto molto richiesto, perché le sue risposte sono memorizzabili per 300 secondi da qualsiasi cache HTTP e accetta lang; il bulk non è memorizzabile in cache e serve a riempire il tuo archivio. La Food Search API e la Barcode Lookup API trasformano testo o un GTIN in un id; questo endpoint trasforma gli id che già possiedi in record. La Nutrition API va nella direzione opposta: la tabella completa per un solo prodotto invece di sei valori di riepilogo per un massimo di 100.
Domande frequenti
Posso inviare codici a barre o termini di ricerca al posto degli id? +
No. Ogni voce deve essere un UUID, altrimenti l'intero batch viene rifiutato con 422. Risolvi i codici a barre con la Barcode Lookup API e i nomi con la Food Search API, salva gli id, poi usali qui.
Una chiamata con 100 id costa 100 richieste? +
No, ne costa una. Il contatore giornaliero e il bucket al secondo avanzano ciascuno di uno per richiesta, a prescindere da quanti id contiene.
Perché non c'è un parametro lang? +
Il bulk restituisce il record grezzo senza i campi di supporto localizzati. Gli array name e ingredients contengono ogni lingua fornita dai contributori, quindi scegli la voce lato client; se ti servono category_localized o allergens_localized, usa GET /v1/foods/{id}?lang= per quel prodotto.
Cosa vede un account Free? +
Un 403 con error Plan upgrade required, required_plan starter e un upgrade_url che punta alla pagina di fatturazione. Il controllo avviene prima della quota giornaliera, quindi quei 403 non consumano le 100 richieste al giorno, e GET /v1/foods/{id} resta disponibile.
Posso ottenere il dettaglio completo dei nutrienti in bulk? +
No. I record bulk contengono solo nutrition_summary. La tabella di oltre 40 nutrienti viene dalla Nutrition API, un id per richiesta; dallo Starter in su non ha un limite giornaliero separato, su Free è limitata a 25 al giorno.
Scopri altri endpoint
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.
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ù →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ù →Inizia subito con API di ricerca multipla di alimenti
Gratis per iniziare. Nessuna carta di credito richiesta.
Ottieni la chiave API Vai alla dashboard