Starter-Tarif

Bulk-Lebensmittelabfrage API

Bis zu 100 Lebensmittel in einer einzigen Anfrage abrufen. Sende ein Array aus IDs oder Barcodes und erhalte die vollständigen Datensätze plus eine Liste dessen, was nicht gefunden wurde – ideal, um einen Essensplan, einen Warenkorb, das Ernährungstagebuch eines Tages oder einen Katalog gescannter Produkte ohne hundert Roundtrips zu befüllen.

200 OK
POST /v1/foods/bulk
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": []
}

Lieber klicken? Probier den Produkt-Explorer oder die Foto-Spielwiese aus.

Was du zurückbekommst

ids[]

1–100 Lebensmittel-IDs im Request-Body – oder:

barcodes[]

1–100 Barcodes (GTIN-8/12/13/14), jeder aufgelöst wie bei der Barcode-Lookup-API, einschließlich Varianten mit führenden Nullen.

data[]

Vollständige Datensätze in der angefragten Reihenfolge; Barcode-Abfragen ergänzen requested_barcode (den gesendeten Code).

not_found[]

Die IDs oder Barcodes ohne Produkt – kein Fehler für den Batch.

?lang=

Optional en/fr/es/de/it/bg, wie bei den Einzelabfragen.

Ab dem Starter-Tarif verfügbar. Tarife ansehen →

Codebeispiele

Dieselbe Anfrage in curl, JavaScript und Python. Ersetze YOUR_API_KEY durch einen Schlüssel aus deinem 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"]}'
            

So funktioniert's

Die Anfrage, Schritt für Schritt

POST /v1/foods/bulk mit Content-Type: application/json, deinem X-API-Key-Header und einem Body der Form {"ids": [...]} oder {"barcodes": [...]} – genau eines von beiden, 1 bis 100 Einträge. ids sind UUID-Strings (die in den Codebeispielen oben sind echte Datensätze zum Testen); Barcodes werden genau wie bei GET /v1/foods/barcode/{code} aufgelöst, sodass ein EAN-13 auch ein Produkt findet, das in seiner UPC-12- oder GTIN-14-Form gespeichert ist, und das Feld barcode des Datensatzes zeigt die gespeicherte Form neben requested_barcode.

Die Validierung läuft, bevor die Datenbank berührt wird, und gilt ganz oder gar nicht. Ein Barcode in ids, beide Felder oder keines, ein leeres Array oder 101 Einträge lehnen den ganzen Batch mit 422 {"error": "Validation Error", "details": [{"field": "ids.3", "message": ...}]} ab. Ein optionales ?lang= (en, fr, es, de, it, bg) lokalisiert Kategorie- und Allergenbezeichnungen wie bei den Einzelabfragen; Namen und Zutaten in anderen Sprachen stehen in den Arrays name und ingredients.

Die Antwort lesen

data ist ein Array von FoodItem-Objekten, aufgebaut vom selben Formatter wie die Lebensmittel-Datenbank-API, sodass ein für den Einzeldatensatz geschriebener Parser unverändert funktioniert — von id, barcode und source bis categories_tags, image_url und allergens. Fehlende Quelldaten sind null, nie ein fehlender Schlüssel.

nutrition_summary enthält energy_kcal, proteins_g, carbs_g, fat_g, sugars_g und fiber_g pro 100 g. Es ist nur dann als Ganzes null, wenn das Produkt gar keine Nährwertzeile hat; fehlt einer Zeile ein Wert, zeigt nur dieser Schlüssel null. Etikettentext wie quantity und serving_size_raw kommt genau so an, wie Mitwirkende ihn getippt haben — parse also defensiv.

Fehlende Einträge, Duplikate und Drift

Die Antwort kann kürzer sein als die Anfrage: Es gibt kein 404 pro Eintrag, aber jede ID und jeder Barcode ohne Produkt steht in not_found, in der Reihenfolge der Anfrage – du musst also nie selbst abgleichen. Eine doppelt gesendete ID oder ein doppelter Barcode kommt als ein Datensatz zurück; dedupliziere vor dem Senden, damit jeder der 100 Plätze zählt.

IDs sind deterministisch, aus der Quelle und deren eigener Produktkennung abgeleitet, sodass ein Produkt über Reimporte hinweg seine id behält. Löst sich eine gespeicherte id nicht mehr auf, ist das Produkt unter dieser Identität nicht mehr im Katalog: Markiere die Zeile als veraltet und löse sie über die Barcode-Abfrage-API oder die Lebensmittel-Suche-API neu auf, statt sie zu löschen.

Kontingent und Rate-Limit-Rechnung

Ein Bulk-Aufruf ist eine Anfrage gegen das Tageskontingent und ein Token aus dem Sekunden-Bucket, egal wie viele IDs. Die Reihenfolge der Middleware ist Authentifizierung, Sekundenlimit, Tarif-Schranke, dann Tageskontingent, sodass ein 401, ein Rate-Limit-429 oder das Starter-403 nie eine Tagesanfrage verbraucht. Ein 422 schon, weil die Validierung nach der Zählung des Kontingents läuft; prüfe UUIDs also auf dem Client.

Lies die Header bei jedem 200: X-RateLimit-Second-Limit, X-RateLimit-Burst-Capacity und X-RateLimit-Second-Remaining für den Bucket pro Schlüssel, X-RateLimit-Account-Limit und X-RateLimit-Account-Remaining für das Sekunden-Aggregat über alle Schlüssel des Kontos sowie X-RateLimit-Daily-Limit, X-RateLimit-Daily-Remaining und X-RateLimit-Daily-Reset (bei normalen Konten) für das gemeinsame Tagesbudget und seinen Reset um Mitternacht UTC. Das POST trägt keinen Cache-Control-Header, am Edge wird also nichts für dich gecacht: Speichere, was du abrufst.

Einen Katalog nachts synchronisieren

Für das Sortiment eines Händlers sende die Barcodes direkt, 100 pro Aufruf, oder speichere die zurückgegebene ID neben deiner SKU und synchronisiere danach per ID. So oder so sucht der nächtliche Job nie: Er liest die gespeicherten Codes, dedupliziert sie, teilt sie in Gruppen zu 100, sendet jede Gruppe hierher und setzt nach jeder fertigen Gruppe einen Checkpoint, damit ein Katalog, der größer ist als das Budget einer Nacht, dort weitermacht, wo er aufgehört hat. Vergleiche updated_at mit deiner Kopie, um zu sehen, was sich geändert hat.

Takte anhand der Header statt mit einem festen Sleep und beobachte X-RateLimit-Daily-Remaining, damit der Sync nicht den Tagesverkehr desselben Kontos aushungert. Braucht eine Ansicht die 40+ Nährstoffe, rufe die Nährwert-API für diese id bei Bedarf auf; sie nimmt eine id pro Anfrage und zählt ebenfalls als Anfrage.

  • IDs deduplizieren, in 100er-Blöcke teilen, pro Block einen Checkpoint setzen.
  • Alles in not_found als veraltet markieren; später erneut prüfen.
  • /nutrients lazy abrufen, pro Produkt, nicht im Sync.

Was du damit baust

Mahlzeitenpläne & Lebensmittelprotokolle

Löse jedes Element des Tagesplans mit einem Aufruf auf.

Warenkorb befüllen

Mach aus einer Liste gespeicherter Lebensmittel-IDs effizient vollständige Datensätze.

Sync-Jobs

Aktualisiere viele gecachte Lebensmittel in Stapeln nach Zeitplan.

Limits pro Tarif

Free Nicht verfügbar: 403 mit required_plan starter (zählt nicht gegen die 100 Anfragen/Tag)
Starter 5.000 Anfragen/Tag, 5/s dauerhaft, Burst 25; bis zu 100 IDs oder Barcodes pro Anfrage
Pro 25.000 Anfragen/Tag, 20/s dauerhaft, Burst 100; bis zu 100 IDs oder Barcodes pro Anfrage
Enterprise 100.000 Anfragen/Tag, 50/s dauerhaft, Burst 250; bis zu 100 IDs oder Barcodes pro Anfrage

Jede Antwort enthält Header X-RateLimit-* mit dem verbleibenden Budget; jede 429 enthält Retry-After . Tarife vergleichen →

Fehler und wie du sie behandelst

403 — Free-Konto; der Body enthält error Plan upgrade required, required_plan starter, current_plan free und eine upgrade_url

Upgrade über die upgrade_url, oder nutze im Free-Tarif GET /v1/foods/{id}

422 — Keines oder beide der Felder ids und barcodes; ein leeres Array oder mehr als 100 Einträge; eine Nicht-UUID in ids oder ein leerer Barcode; details[] nennt die fehlerhafte Position

Clientseitig validieren und deduplizieren; Barcodes in barcodes[] senden, nicht in ids[]

429 — Bucket pro Schlüssel oder Konto leer, oder X-RateLimit-Daily-Remaining hat 0 erreicht (Body: Daily quota exceeded)

Pausiere für die Sekunden aus Retry-After; im Tagesfall ist das die Zeit bis Mitternacht UTC

401 — X-API-Key-Header fehlt, oder der Schlüssel ist ungültig oder widerrufen

Prüfe den Header-Namen und den Schlüssel im Dashboard

503 — Der Speicher für Kontingent oder Rate-Limit ist nicht erreichbar; die API schlägt geschlossen fehl (fail closed)

Mit Backoff wiederholen; die Anfrage wurde nicht gezählt

Im Vergleich zu anderen APIs

Gegenüber dem GET für einen einzelnen Datensatz liegt der Gewinn bei Roundtrips und Kontingent: 100 Datensätze für eine Anfrage statt 100 Anfragen. Das GET gewinnt, wenn viele Clients dasselbe beliebte Produkt lesen, weil seine Antworten von jedem HTTP-Cache 300 Sekunden lang gecacht werden können und es lang akzeptiert; Bulk ist ungecacht und füllt deinen eigenen Speicher. Die Lebensmittel-Suche-API und die Barcode-Abfrage-API machen aus Text oder einer GTIN eine id; dieser Endpunkt macht aus IDs, die du schon hast, Datensätze. Die Nährwert-API geht den umgekehrten Weg: die vollständige Tabelle für ein Produkt statt sechs Zusammenfassungswerte für bis zu 100.

Zum vollständigen Vergleich der Lebensmitteldaten-APIs →

Häufige Fragen

Kann ich Barcodes oder Suchbegriffe statt IDs senden? +

Nein. Jeder Eintrag muss eine UUID sein, sonst wird der ganze Stapel mit 422 abgelehnt. Löse Barcodes über die Barcode-Abfrage-API und Namen über die Lebensmittel-Suche-API auf, speichere die IDs und verwende sie dann hier.

Kostet ein Aufruf mit 100 IDs 100 Anfragen? +

Nein, er kostet eine. Der Tageszähler und der Sekunden-Bucket bewegen sich je Anfrage um eins, unabhängig davon, wie viele IDs darin stecken.

Warum gibt es keinen lang-Parameter? +

Bulk liefert den rohen Datensatz ohne die lokalisierten Hilfsfelder. Die name- und ingredients-Arrays enthalten jede Sprache, die Mitwirkende geliefert haben, wähle den Eintrag also auf dem Client; brauchst du category_localized oder allergens_localized, nutze für dieses Produkt GET /v1/foods/{id}?lang=.

Was sieht ein Free-Konto? +

Ein 403 mit error Plan upgrade required, required_plan starter und einer upgrade_url, die auf die Abrechnungsseite zeigt. Die Schranke läuft vor dem Tageskontingent, diese 403er fressen also nicht die 100 Anfragen pro Tag, und GET /v1/foods/{id} bleibt verfügbar.

Kann ich die vollständige Nährwert-Aufschlüsselung im Bulk bekommen? +

Nein. Bulk-Datensätze tragen nur nutrition_summary. Die Tabelle mit 40+ Nährstoffen kommt von der Nährwert-API, eine id pro Anfrage; ab Starter hat sie kein separates Tageslimit, im Free-Tarif ist sie auf 25 pro Tag begrenzt.

Leg jetzt los mit der Bulk-Lebensmittelabfrage API

Kostenlos starten. Keine Kreditkarte nötig.

API-Schlüssel holen Zum Dashboard