data.foodintegrityproject.org / API

API v1

A barcode-keyed read API over packaged food: products, ingredients, certifications, and the research behind the insights. All responses are JSON.

Base URL

https://data.foodintegrityproject.org/api/v1

Errors use standard HTTP status codes with a body of { "error": { "code": "...", "message": "..." } }.

Authentication

Endpoints

GET/api/v1/products/:barcode

The main consumer endpoint. Returns a product with its ingredients, nutrition, claims, and triggered insights.

Path params

  • barcode — UPC/EAN, digits only

Query params

  • include_findings (bool, default true) — expand research findings inline
  • enrich_if_thin (bool, default false) — if the data quality score is low, trigger Open Food Facts enrichment synchronously (may slow the response)

200 OK — product found

{
  "variant": {
    "barcode": "0123456789012",
    "package_size": "12 oz",
    "package_format": "bag",
    "region": "US",
    "data_quality_score": 0.82,
    "source": "verified"
  },
  "line": {
    "slug": "tortilla-chips-original",
    "display_name": "Tortilla Chips (Original)",
    "category": "snacks",
    "nova_class": "nova_3"
  },
  "brand": { "slug": "acme", "display_name": "Acme", "parent_company": "Acme Holdings" },
  "ingredients": [
    { "position": 1, "raw_text": "corn", "slug": "corn", "category": "whole_food" },
    { "position": 2, "raw_text": "soybean oil", "slug": "soybean-oil", "category": "oil_seed" }
  ],
  "nutrition": { "calories_per_100g": 490, "sodium_mg_per_100g": 410 },
  "claims": [
    {
      "scheme": { "slug": "non-gmo-project-verified", "name": "Non-GMO Project Verified", "authority": "Non-GMO Project" },
      "status": "active",
      "source_level": "line",
      "evidence_sources": ["api_verified", "package_detected"]
    }
  ],
  "insights": [
    {
      "rule_slug": "high-gmo-risk-ingredients",
      "type": "classification",
      "severity": "caution",
      "text": "Contains soybean oil and corn, both commonly derived from GMO crops unless certified.",
      "evidence": { "matched_ingredients": ["soybean-oil", "corn"] },
      "findings": [ { "slug": "...", "title": "...", "evidence_strength": "established" } ]
    }
  ],
  "meta": { "last_evaluated_at": "2026-05-19T20:00:00Z", "needs_enrichment": false }
}

404 Not Found — barcode not in system

{
  "error": { "code": "product_not_found", "message": "..." },
  "submission_url": "/api/v1/submissions"
}
POST/api/v1/products/:barcode/enrich

Trigger an Open Food Facts lookup and merge for an existing thin product. No auth required, rate-limited. Returns the enriched product along with a trace id.

{ "status": "enriched", "trace_id": "...", "variant": { "...": "..." } }
POST/api/v1/submissions

User submits photos to seed or enrich a product. Content-Type multipart/form-data.

Fields

  • barcode (optional) — if known
  • images[] — 1–6 image files (front, back/ingredients, nutrition panel)
  • notes (optional) — free text from the submitter

Images run through an OpenRouter vision call. The submission auto-publishes when extraction_confidence ≥ 0.85 and the brand already exists; otherwise it is marked needs_review for a contributor.

201 Created

{
  "submission_id": "...",
  "status": "published",
  "extraction_confidence": 0.91,
  "extracted": { "...": "..." },
  "persisted": { "...": "..." },
  "trace_id": "..."
}
POST/api/v1/submissions/photo

Single-image submission with an explicit panel type. Content-Type multipart/form-data. Same extraction and persistence logic as /submissions.

Fields

  • barcode (optional)
  • image — a single image file
  • panel_typefront, back, ingredients, nutrition, or auto

201 Created

{ "submission_id": "...", "status": "needs_review", "panel_type": "ingredients", "extraction_confidence": 0.72 }
GET/api/v1/submissions/:id

Poll a submission’s status.

{ "submission_id": "...", "status": "published", "product_id": "...", "extraction_confidence": 0.91 }
GET/api/v1/schemes

List all active certification schemes.

{
  "schemes": [
    {
      "slug": "non-gmo-project-verified",
      "name": "Non-GMO Project Verified",
      "authority": "Non-GMO Project",
      "scope_summary": "...",
      "badge_image_url": "..."
    }
  ]
}
GET/api/v1/brands

Search for brands by name (fuzzy, across display name and aliases).

Query params

  • q — search query
  • limit — default 20, max 100
{
  "brands": [
    { "slug": "general-mills", "display_name": "General Mills", "parent_company": "General Mills, Inc." }
  ]
}
GET/api/v1/ingredients/:slug

Pull canonical info and research for one ingredient.

{
  "ingredient": {
    "slug": "carrageenan",
    "canonical_name": "Carrageenan",
    "aliases": ["E407", "Irish moss extract"],
    "category": "thickener",
    "description": "..."
  },
  "findings": [
    {
      "slug": "...",
      "title": "...",
      "summary": "...",
      "evidence_strength": "emerging",
      "finding_type": "review_article",
      "citation": { "...": "..." }
    }
  ]
}
POST/api/v1/insights/evaluate

Evaluate an ad-hoc ingredient list without a barcode. Useful for restaurant menus, bulk bin items, or hypothetical formulations.

Body

{
  "ingredients": ["corn", "soybean oil", "salt", "natural flavors", "soy lecithin"],
  "nutrition": { "sodium_mg_per_100g": 600 }
}

200 OK

{
  "ingredients_parsed": [ { "raw_text": "...", "matched_slug": "...", "confidence": 0.95 } ],
  "insights": [ /* same shape as /products/:barcode */ ]
}

Planned endpoints

Specified but not yet live. Shapes may change before release.

GET/api/v1/brands/:slugplanned — not yet live

Get a brand and its product lines.

GET/api/v1/lines/:idplanned — not yet live

Get a product line, its canonical recipe, claims, and variants.

POST/api/v1/products/:barcode/refresh-claimsplanned — not yet live

Re-run all enabled scheme adapters against the certifier APIs.

Contributor endpoints

Auth required (Supabase JWT). Used by the contributor dashboard to manage submissions, rules, findings, schemes, claims, brands, and lines.

Rate limits

Versioning

The path includes /v1/. Breaking changes get a new major version. Additive changes do not.