API de reconnaissance d'images alimentaires
Transformez une photo en données alimentaires. Quatre endpoints de vision couvrent tout le parcours caméra : décoder un code-barres, identifier un produit par sa face avant, lire l'étiquette nutritionnelle et les ingrédients, ou analyser une assiette avec des estimations de portions — avec correspondance parmi 6,1 M de produits, en six langues dont le cyrillique.
curl -X POST -H "X-API-Key: food_•••" \
-F "[email protected]" \
"https://foodbase.dev/v1/vision/product"
{
"extracted": {
"name": "Масло краве",
"brand": "Bulgaricum",
"quantity": "250g",
"lang": "bg",
"confidence": 0.95
},
"matches": [
{
"score": 0.95,
"product": {
"id": "c5b352b5-...",
"name_default": "Краве масло 82%"
}
}
],
"cached": false
} Vous préférez cliquer ? Essayez l'explorateur de produits ou le bac à sable photo.
Ce que vous obtenez
POST /vision/barcode
Décode un EAN-13/UPC sur une photo et cherche le produit. Gratuit — 0 crédit.
POST /vision/product
Identifie un produit par sa face avant et le rapproche du catalogue. 3 crédits.
POST /vision/label
Lit par OCR le tableau nutritionnel et la liste des ingrédients. 4 crédits.
POST /vision/meal
Identifie les plats d'une assiette avec estimations de portions et de kcal. 5 crédits.
confidence
Score calibré de 0 à 1 sur chaque extraction — pour décider quand demander à l'utilisateur.
cached
Les images identiques sont servies depuis le cache — même réponse, instantanée.
Disponible sur tous les forfaits grâce aux crédits IA mensuels — chaque appel a un prix fixe en crédits, et chaque forfait (Free compris) inclut une dotation de crédits. Voir les forfaits →
Exemples de code
La même requête en curl, JavaScript et Python. Remplacez YOUR_API_KEY par une clé de votre tableau de bord.
curl "https://foodbase.dev/v1/vision/product" \
-H "X-API-Key: YOUR_API_KEY" \
-F "[email protected]"
const form = new FormData();
form.append("image", fileInput.files[0]); // a File/Blob from an <input type="file">
const res = await fetch("https://foodbase.dev/v1/vision/product", {
method: "POST",
headers: { "X-API-Key": "YOUR_API_KEY" },
body: form,
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
import requests
with open("photo.jpg", "rb") as f:
res = requests.post(
"https://foodbase.dev/v1/vision/product",
headers={"X-API-Key": "YOUR_API_KEY"},
files={"image": f},
timeout=30,
)
res.raise_for_status()
data = res.json()
Comment ça marche
Quel endpoint pour quelle photo
Les quatre opérations prennent un seul champ multipart/form-data nommé image. Le serveur analyse les octets, pas le nom de fichier : JPEG, PNG ou WebP, jusqu'à 8 Mo, sinon l'envoi est rejeté avant l'exécution de tout modèle. Les photos sont redressées d'après l'EXIF et redimensionnées à 1024 px sur le plus grand côté : une capture en pleine résolution ne coûte que du temps d'envoi.
POST /v1/vision/barcode décode EAN-13, EAN-8, UPC-A, UPC-E et Code-128 par vision par ordinateur classique et cherche le code exactement comme GET /foods/barcode/{code}. Le corps du 200 est { barcode, product } avec la fiche complète du catalogue (id, name_default, brand, nutrition_summary et le reste). Aucun modèle de langage n'intervient : il coûte 0 crédit et est décompté comme un appel de données.
Les trois autres sont des appels IA. /vision/product lit une face avant et produit extracted { name, brand, quantity, lang, confidence } plus des matches classés. /vision/label transcrit un tableau nutritionnel en valeurs pour 100 g, ingredients_text, allergens et serving ; un tableau qui n'imprime que des valeurs par portion est converti en pour 100 g par le code quand la taille de portion est imprimée (basis per_100g, converted: true) ; sinon, les champs pour 100 g valent null et les valeurs imprimées reviennent sous per_serving (basis per_serving). /vision/meal renvoie items[] avec les plats reconnus et des estimations de portion. Chaque réponse porte request_id et cached.
- Une requête sans champ image renvoie un 422 Validation Error avec details[].field = "image".
Lire une réponse de /vision/product
extracted.lang est la langue lue sur l'emballage (bg pour une étiquette en cyrillique) et pilote une recherche dans le catalogue adaptée à la langue. confidence va de 0 à 1 et conditionne cette recherche : le catalogue n'est interrogé que si confidence vaut au moins 0.3 et qu'un nom a été lu ; sinon matches est vide.
matches contient jusqu'à 5 produits, du meilleur au moins bon, chacun { score, product } dans la même forme FoodItem complète qu'une fiche de l'API de base de données alimentaire. score dérive de confidence et du rang : la meilleure correspondance porte la confidence elle-même et chaque entrée suivante a un score plus bas. Conservez matches[0].product.id ; les id sont stables d'une réimportation à l'autre.
Un échec ressemble à cette réponse à la photo d'un petit produit : {"matches":[],"extracted":{"lang":"","name":"","brand":"","quantity":"","confidence":0},"request_id":"bcca8231-f335-4468-81bf-e587b614d9a4","cached":true}. Des chaînes vides et confidence 0 signifient qu'aucun nom n'a pu être lu ; cached: true signifie que les mêmes octets avaient déjà été vus, et l'appel a tout de même coûté 3 crédits.
Étiquettes et repas : lu ou estimé
/vision/label est une transcription, pas une inférence. energy_kcal, fat_g, saturated_fat_g, carbs_g, sugars_g, fiber_g, proteins_g et salt_g sont lus tels qu'imprimés, et tout ce qui ne figure pas sur l'étiquette revient null, jamais deviné. Un code-barres lisible sur la même photo est renvoyé dans extracted.barcode et recherché : s'il est trouvé, product contient la FoodItem complète, sinon product vaut null.
/vision/meal fait l'inverse, et son champ disclaimer le dit. Chaque élément a dish, kind, portion_g_est et confidence, plus match quand le plat a été rapproché d'un aliment générique USDA : id, name_default, per_100g { energy_kcal, proteins_g, carbs_g, fat_g } et estimated_kcal, qui vaut per_100g.energy_kcal multiplié par portion_g_est divisé par 100. Les éléments sont soit des plats entiers (kind "dish" : un burger, des lasagnes), soit les composants séparés d'une assiette (kind "component" : riz, poulet grillé, salade), jamais un plat avec ses propres composants : estimated_total_kcal, la somme des éléments qui en ont un, ne compte donc rien deux fois ; il vaut null quand aucun élément n'en a. La correspondance utilise des aliments génériques en anglais — USDA FNDDS pour les plats tels que consommés (lasagne, burritos, pad thai), puis USDA SR Legacy pour les ingrédients — donc match.name_default est en anglais quelle que soit la photo, et un élément sans correspondance fiable reçoit match: null plutôt qu'un mauvais aliment.
- Affichez le texte du disclaimer aux utilisateurs finaux des estimations de repas ; un plat avec match: null coûte quand même 5 crédits.
Crédits, remboursements et limite de débit de la vision
Les crédits sont débités avant l'inférence : 3 pour product, 4 pour label, 5 pour meal. La dotation mensuelle est partagée par toutes les clés du compte (Free 20, Starter 500, Pro 1 300, Enterprise 3 000) et se réinitialise le premier du mois UTC. Quand elle ne peut plus couvrir un appel, les crédits des packs de recharge ponctuels (achetés sur la page Billing du tableau de bord, valables 12 mois) prennent le relais. Les réponses IA portent X-Credits-Limit, X-Credits-Remaining (mensuel plus recharge), X-Credits-Topup-Remaining et X-Credits-Reset ; GET /v1/credits renvoie gratuitement les deux soldes.
Être à court donne un 402, pas un 429 : { "error": "Insufficient credits", "message": "This call costs 3 credits and your free plan's monthly allowance of 20 is exhausted, with no top-up credits left. Buy more at https://foodbase.dev/dashboard/billing (they apply instantly), or wait for the reset on 2026-12-01.", "top_up_url": "https://foodbase.dev/dashboard/billing" }. Les remboursements n'ont lieu que si la requête n'a jamais abouti à une réponse : image rejetée (413 ou 422), champ manquant (422), défaillance du fournisseur (502, le message se termine par "You were not charged.") ou vision désactivée (503). Les réponses en cache sont facturées plein tarif, volontairement.
Les appels IA ont leur propre limite par seconde, sans rafale : 1/s sur Free et Starter, 2/s sur Pro, 5/s sur Enterprise par clé, et le triple pour l'ensemble du compte. Les réponses portent X-RateLimit-Vision-Limit et X-RateLimit-Vision-Remaining ; la dépasser donne un 429 avec Retry-After: 1 et aucun débit, car le limiteur s'exécute avant la déduction.
Le parcours de scan et la photo
Le moins cher d'abord. Décodez le code-barres sur l'appareil et appelez l'API de recherche par code-barres, ou laissez /vision/barcode le décoder pour 0 crédit. Seulement s'il n'y a pas de code-barres, ou si la recherche renvoie 404, envoyez la face avant de l'emballage à /vision/product. Avec matches[0].product.id, récupérez le détail pour 100 g via l'API de nutrition ou un avis en langage clair via l'API d'analyse IA des aliments.
La qualité de la photo détermine la confidence. Pour /vision/product, cadrez la face avant avec le nom, la marque et le format lisibles et rien d'autre dans le champ. Pour /vision/label, posez le tableau à plat, remplissez le cadre avec le tableau nutritionnel et le paragraphe des ingrédients, et incluez le code-barres s'il tient. Pour /vision/barcode, le message 422 du serveur fait foi : remplissez le cadre avec le code-barres, évitez les reflets, gardez-le net.
- Réessayez un 502 après une courte attente ; vous avez été remboursé. Ne renvoyez pas un 200 à faible confidence : reprenez plutôt la photo.
Ce que vous pouvez créer
Journal alimentaire en photo
Photographiez un produit ou un repas et enregistrez-le — sans saisie ni chasse au code-barres.
Capture d'étiquettes
Numérisez valeurs nutritionnelles et ingrédients de n'importe quel emballage, même pour des produits absents des bases de données.
Repli intelligent pour le scanner
Code-barres illisible ? Basculez sur la reconnaissance de la face avant dans le même parcours.
Limites par forfait
| Free | 20 crédits IA/mois ; 1 requête IA/s par clé ; /vision/barcode compte dans les 100 requêtes/jour |
|---|---|
| Starter | 500 crédits IA/mois ; 1 requête IA/s par clé ; /vision/barcode compte dans les 5 000 requêtes/jour |
| Pro | 1 300 crédits IA/mois ; 2 requêtes IA/s par clé ; /vision/barcode compte dans les 25 000 requêtes/jour |
| Enterprise | 3 000 crédits IA/mois ; 5 requêtes IA/s par clé ; /vision/barcode compte dans les 100 000 requêtes/jour |
Chaque réponse contient des en-têtes X-RateLimit-* indiquant le budget restant ; chaque 429 contient Retry-After . Comparer les forfaits →
Erreurs et comment les gérer
402 — Crédits IA mensuels et crédits de recharge épuisés ; le corps indique le prix, votre dotation, la date de réinitialisation et une top_up_url.
Achetez un pack de crédits (appliqué instantanément), attendez X-Credits-Reset ou passez au forfait supérieur. /vision/barcode fonctionne toujours.
404 — /vision/barcode a décodé un code absent du catalogue ; le corps le renvoie.
Ne réessayez pas. Basculez sur /vision/product avec une photo de la face avant.
413 — Fichier envoyé de plus de 8 Mo.
Réduisez côté client ; le serveur redimensionne de toute façon à 1024 px. Crédits remboursés.
422 — Image absente, illisible, au mauvais format, ou aucun code-barres dans le cadre.
Lisez details[] ou message et reprenez la photo. Crédits remboursés.
429 — Limite par seconde de la vision dépassée pour la clé ou le compte.
Attendez Retry-After (1 seconde) et renvoyez. Rien n'a été débité.
502 — Le fournisseur de vision a échoué en cours d'appel.
Réessayez une fois après une pause ; le message confirme que vous n'avez pas été débité.
503 — Vision non configurée, ou limiteur ou stockage des crédits injoignable.
Réessayez avec un délai croissant. Rien n'a été débité.
Comparaison avec d'autres API
La plupart des services photo-vers-aliment renvoient une étiquette pour ce qu'ils croient voir et vous laissent trouver le produit. FoodBase résout dans le même appel : extraction plus correspondances classées parmi les 6,1 M de produits du catalogue, ou une fiche liée quand la photo d'une étiquette porte un code-barres. Il distingue la lecture de l'estimation : les valeurs d'étiquette sont transcrites ou null, et seul /vision/meal estime, avec un champ disclaimer. La contrepartie : une mauvaise photo donne une liste de correspondances vide et coûte quand même ses crédits, donc guider la prise de vue dans votre interface est vite rentabilisé.
Voir la comparaison complète des API de données alimentaires →
Questions fréquentes
/vision/product coûte-t-il des crédits quand rien ne correspond ? +
Oui. Les crédits sont débités avant l'inférence, et un 200 avec matches: [] est un appel abouti. Reprenez la photo plutôt que de la renvoyer ; un renvoi est une réponse en cache facturée plein tarif.
Pourquoi une réponse en cache a-t-elle quand même été facturée ? +
Les réponses en cache coûtent volontairement autant que les appels neufs ; le cache rend les répétitions rapides et cohérentes, pas gratuites. Dédoublonnez les photos identiques côté client avant un second envoi.
/vision/label peut-il compléter des valeurs absentes de l'étiquette ? +
Non. Il transcrit le tableau et renvoie null pour tout ce qui n'est pas imprimé. Pour une interprétation de ces valeurs, envoyez l'id du produit lié à l'API d'analyse IA des aliments.
La limite de débit de la vision est-elle la même que ma limite d'API ? +
Non. Les appels IA utilisent un compteur séparé et plus bas : 1/s sur Free et Starter, 2/s sur Pro, 5/s sur Enterprise par clé, et le triple sur l'ensemble des clés. Seul /vision/barcode utilise la limite et le quota quotidien de l'API de données.
Comment vérifier les crédits restants sans en dépenser ? +
Appelez GET /v1/credits avec votre clé. Il renvoie le forfait, la dotation mensuelle, les crédits utilisés et la date de réinitialisation, sans compter ni dans les crédits ni dans le quota quotidien.
Découvrez d'autres endpoints
API d'analyse IA des aliments
Un seul appel transforme les données brutes d'un produit en quelque chose que vous pouvez montrer à un utilisateur : un résumé en deux phrases, des points forts et des points de vigilance calculés à partir des données nutritionnelles avec des seuils publiés, les allergènes déclarés, la compatibilité avec les régimes en précisant d'où vient chaque réponse, et le niveau de transformation — en six langues, strictement fondé sur les données d'étiquette du produit.
En savoir plus →API de recherche par code-barres
Scannez ou tapez un code-barres, obtenez le produit. Résolvez n'importe quel code EAN-13 ou UPC en fiche alimentaire — marque, catégorie, Nutri-Score et résumé nutritionnel — en une seule requête. Conçue pour les applis de scan.
En savoir plus →API de nutrition
Allez au-delà des macros principales. Obtenez le détail de plus de 40 nutriments par produit — énergie, protéines, glucides, lipides, sucres, fibres, sodium, vitamines et minéraux — tous pour 100 g, pour n'importe quel aliment par ID.
En savoir plus →Commencez à développer avec l'API de reconnaissance d'images alimentaires
Gratuit pour démarrer. Sans carte bancaire.
Obtenir une clé API Aller au tableau de bord