Introduction
NutriGraphAPI
Reference
NutriGraphAPI is a REST API returning food intelligence across 5M+ UPC-indexed products. Every response contains two root objects: scraped_data (on-label manufacturer declarations) and analysed_data (AI-qualified intelligence layer). Always build against analysed_data for application logic.
Full payload on the free tier. The Developer plan returns the identical response as paid plans. Every attribute, every score, every flag — from call one. The only limit is volume: 1,000 calls/month.
Base URL: https://barcode-api-140543331861.asia-south1.run.app/api
Authentication: X-API-Key header — request your key
Format: JSON, UTF-8, always
Authentication
Authentication
All requests must include your API key in the X-API-Key header. Keys are issued per legal entity. To request a key, email support@nutrigraphapi.com.
Keep your key private. Do not embed it in client-side code, commit it to public repositories, or expose it in browser network requests. If compromised, contact us immediately for a replacement.
curl -i \
-H "X-API-Key: YOUR_API_KEY" \
"https://barcode-api-140543331861.asia-south1.run.app/api/lookup?barcode=039978009579"
Getting started
Quick-start
Your first call in four languages. All return the identical full payload.
Node.js
const API_KEY = 'YOUR_API_KEY';
const barcode = '039978009579';
const res = await fetch(
`https://barcode-api-140543331861.asia-south1.run.app/api/lookup?barcode=${barcode}`,
{ headers: { 'X-API-Key': API_KEY } }
);
const { analysed_data } = await res.json();
// Access any attribute:
const nova = analysed_data.additionalInfo.nova_group;
const isVegan = analysed_data.additionalInfo.dietary_preference.Vegan;
const gluten = analysed_data.npiFoodPackagesAllergensIntolerances.glutenQualified;
Python
import requests
API_KEY = 'YOUR_API_KEY'
barcode = '039978009579'
resp = requests.get(
'https://barcode-api-140543331861.asia-south1.run.app/api/lookup',
params={'barcode': barcode},
headers={'X-API-Key': API_KEY}
)
data = resp.json()['analysed_data']
nova = data['additionalInfo']['nova_group']
is_vegan = data['additionalInfo']['dietary_preference']['Vegan']
allergens = data['npiFoodPackagesAllergensIntolerances']
clean = data['cleanLabel'] # 30+ fields
Swift
let apiKey = "YOUR_API_KEY"
let barcode = "039978009579"
let url = URL(string: "https://barcode-api-140543331861.asia-south1.run.app/api/lookup?barcode=\(barcode)")!
var request = URLRequest(url: url)
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
let (data, _) = try await URLSession.shared.data(for: request)
let product = try JSONDecoder().decode(NutriGraphProduct.self, from: data)
Endpoints
Product lookup
Returns the full intelligence payload for a product identified by UPC-12 barcode. Both scraped_data and analysed_data are returned on every successful response.
Parameters
| Parameter | Type | Required | Description |
| barcode | string | Required | UPC-12 barcode of the product. Leading zeros must be preserved. Example: 039978009579 |
Example request
curl -i \
-H "X-API-Key: YOUR_API_KEY" \
"https://barcode-api-140543331861.asia-south1.run.app/api/lookup?barcode=039978009579"
Example response (condensed)
{
"scraped_data": { /* raw on-label manufacturer data */ },
"analysed_data": {
"generalData": {
"upc12": "039978009579",
"brandName": "Bob's Red Mill",
"category": "Steel Cut Oats",
"numberOfIngredients": 1
},
"additionalInfo": {
"nova_group": "1",
"nutriscore_grade": "B",
"ecoscore": "B",
"dietary_preference": {
"Vegan": true, "Vegetarian": true,
"KetoFriendly": false, "LowFodmap": false
},
"religious_labels": {
"Kosher": true, "Halal": false,
"Jain": false, "Hindu": false
},
"sustainability_labels": {
"PlantBased": true, "Recycled": true
}
},
"npiFoodPackagesAllergensIntolerances": {
"glutenLevelStated": "Gluten-free",
"glutenQualified": "Yes (certified on pack)",
"falcpaCommonAllergensStated": "No",
"additionalInfo": {
"traces": "May be processed in facility with tree nuts"
}
},
"cleanLabel": {
"artificialColorsQualified": "No",
"preservativesQualified": "No",
"gmoPresenceQualified": "Non-GMO",
"recognizableIngredientsQualified": "Yes"
},
"claims": {
"certifications": ["USDA Organic", "Non-GMO Project Verified", "Kosher"]
},
"ingredients": [
{
"name": "Organic Whole Grain Oats",
"allergens": { "Gluten": false, "Peanuts": false },
"dietary_preference": { "Vegan": true },
"religious_labels": { "Kosher": true }
}
]
}
}
Endpoints
Request a product
Submit a UPC that returned 404 for onboarding. Products are typically added within 48 hours. Bulk UPC lists are available on Enterprise plans — contact
support@nutrigraphapi.com.
| Body field | Type | Required | Description |
| barcode | string | Required | The UPC-12 that returned 404 |
| product_name | string | Optional | Helps us onboard faster |
| brand | string | Optional | Brand name |
curl -X POST \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"barcode":"012345678901","product_name":"Example Product","brand":"Example Brand"}' \
"https://barcode-api-140543331861.asia-south1.run.app/api/request"
Response schema
Allergens
Path: analysed_data.npiFoodPackagesAllergensIntolerances
Always use Qualified fields for safety logic. The Stated field reflects what the manufacturer declared on-label. The Qualified field is our AI-verified conclusion. For allergen filtering in your application, always use Qualified.
eggStatedstring— Egg allergen as declared on label
eggQualifiedstring— AI-verified egg allergen status
dairyStated / dairyQualifiedstring pair
glutenLevelStatedstring— e.g. "Gluten-free", "Contains gluten"
glutenQualifiedstring— AI-verified gluten status
fishStated / fishQualifiedstring pair
caseinStated / caseinQualifiedstring pair— Casein tracked separately from dairy
falcpaCommonAllergensStatedstring— FDA Big-9 declaration
fdaRegulatedAllergensstring— FALCPA summary
additionalInfo.tracesstring— May-contain / cross-contamination statement
ingredients[].allergensobject— Per-ingredient allergen tree
Peanuts, Milk, Egg, Wheat, Soy, Fish, Shellfish, Sesame, TreeNutsboolean
Response schema
Clean label
Path: analysed_data.cleanLabel — 30+ fields, each with a Stated (on-label) and Qualified (AI-verified) variant.
artificialColorsStated / artificialColorsQualifiedstring
artificialFlavorsStated / artificialFlavorsQualifiedstring
artificialSweetenersStated / artificialSweetenersQualifiedstring
preservativesStated / preservativesQualifiedstring
gmoPresenceStated / gmoPresenceQualifiedstring— e.g. "Non-GMO Project Verified"
highFructoseCornSyrupStated / highFructoseCornSyrupQualifiedstring
naturalColorsStated / naturalColorsQualifiedstring
sugarAlcoholsStated / sugarAlcoholsQualifiedstring
hormonesStated / antibioticsStatedstring
madeInUsaStatedstring
countOfIngredientsQualifiedstring— e.g. "Low (1 main ingredient)"
recognizableIngredientsQualifiedstring— "Yes" / "No"
Response schema
Dietary & religious
Path: analysed_data.additionalInfo — available at both product level and nested inside each ingredients[] item.
dietary_preferenceobject
Veganboolean
Vegetarianboolean
KetoFriendlyboolean
LowFodmapboolean
Pescatarianboolean
NoRedMeatboolean
religious_labelsobject
Kosherboolean
Halalboolean
Jainboolean
Hinduboolean
Response schema
Nutrition
Path: analysed_data.nutritionalInformation — two sub-objects: stated (from manufacturer) and qualified (AI-backfilled and verified). Per 100g with daily values.
Backfill flag. When qualified.backfillNutrientsProcessed is true, values were AI-enriched rather than sourced directly from a label. Reliable, but surface this distinction in clinical contexts.
stated.macronutrients[]array— Energy, Fat, SatFat, Carbs, Sugars, Fiber, Protein, Sodium
stated.micronutrients[]array— Iron + declared micros
qualified.macronutrients[]array— AI-verified macros + kJ
qualified.micronutrients[]array— Iron, Potassium, VitD, Calcium, VitA, VitC
each nutrient.valuefloat— Per 100g
each nutrient.dailyValuefloat— % Daily Value
each nutrient.sourcestring— Data provenance
servingSize.servingSizefloat— In grams
servingSize.servesPerPackinteger
qualified.backfillNutrientsProcessedboolean
Response schema
Quality scores
Path: analysed_data.additionalInfo and analysed_data.food_safety_labels — six scores returned in every response.
nova_groupstring "1"–"4"— NOVA processing level. 1=unprocessed, 4=ultra-processed
nutriscore_gradestring A–E— Nutri-Score nutritional quality
ecoscorestring A–E— Environmental impact
food_safety_labels.Organicboolean
food_safety_labels.NoGMOboolean
food_safety_labels.Carcinogenicboolean— Known carcinogenic ingredient flag
food_safety_labels.ProductRecallsboolean— Active recall flag
average_customer_ratingfloat— Marketplace rating
Response schema
Sustainability
Path: analysed_data.additionalInfo.sustainability_labels — six flags at product and ingredient level.
PlantBasedboolean
Recycledboolean— Recycled / recyclable packaging
SustainablePackagingboolean
OrganicPositioningboolean
SocialResponsibilityboolean
AnimalWelfareboolean
claims.sustainability.packaging[]string array— On-pack packaging claims
claims.sustainability.environmentalClaims[]string array
Reference
Error codes
All error responses use the same JSON envelope:
{
"error": "PRODUCT_NOT_FOUND",
"upc": "012345678901",
"message": "Submit via POST /api/request",
"request_id": "req_abc123xyz"
}
| Code | Meaning | Action |
| 200 OK | Successful response | Read analysed_data |
| 401 Unauthorized | Missing or invalid API key | Check your X-API-Key header |
| 404 Not Found | UPC not in database | Submit via POST /api/request — onboarded within 48h |
| 429 Too Many Requests | Rate limit exceeded | Wait for quota reset (1st of month for monthly plans) |
| 500 Server Error | Unexpected server error | Retry with exponential backoff. Contact support if persistent. |
Reference
Rate limits
| Plan | Monthly quota | On 429 |
| Developer (free) | 1,000 calls/month | Returns 429 until month resets |
| Professional | 100,000 calls | Overage billed at plan rate |
| Enterprise | 1,000,000 calls | Overage billed at plan rate |
Quotas reset on the 1st of each calendar month for monthly plans, or on the annual anniversary for annual plans.
Reference
Caching
Manufacturers reformulate without notice, so treat the cache as a short performance window rather than a substitute for the source — a record that has gone stale carries exactly the risk the lookup was there to remove. Cache for up to 24 hours, keyed on UPC-12, to avoid redundant calls, then revalidate. Use the data_last_updated field to selectively invalidate.
const CACHE_TTL = 86400; // 24 hours in seconds
async function getProduct(upc) {
const cacheKey = `nutrigraph:${upc}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const res = await fetch(
`https://barcode-api-140543331861.asia-south1.run.app/api/lookup?barcode=${upc}`,
{ headers: { 'X-API-Key': API_KEY } }
);
const data = await res.json();
await redis.setex(cacheKey, CACHE_TTL, JSON.stringify(data));
return data;
}
Permitted under Terms. Caching API responses for performance is explicitly permitted.
Section 3 of the Terms sets 24 hours as the ceiling rather than a suggestion: cached responses stay inside your application and are not retained, exported or accumulated beyond that window. Records change when manufacturers reformulate, so the limit protects your users as much as our data.
Reference
Changelog
June 2026 — v1.0
Initial public release. 5M+ products. Full analysed_data layer. Per-ingredient allergen trees. 30+ clean label fields. NovaScore, EcoScore, Nutri-Score. Four religious compliance labels. Six sustainability flags.
Questions or issues? Email support@nutrigraphapi.com — we respond within 24 hours.