# Barcode Lookup API — GTIN/EAN/UPC/ISBN to product data (title, brand, images, nutrition, retailer offers) via Open Food Facts and UPCitemdb, with check-digit validation

> Barcode → one merged product: title/brand/category/image/description + dimensions/model + retailer offers&prices (UPCitemdb) + nutrition/ingredients/allergens if food (OFF). Includes check-digit validation, GTIN-13 normalization and issuing-country. source=auto merges both.
> ReefAPI engine `barcode` · 7 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/barcode/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed or blocked calls are free.
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /barcode/v1/lookup — 1 credit
Barcode → one merged product: title/brand/category/image/description + dimensions/model + retailer offers&prices (UPCitemdb) + nutrition/ingredients/allergens if food (OFF). Includes check-digit validation, GTIN-13 normalization and issuing-country. source=auto merges both.

**Parameters:**
- `barcode` (string, required) — The barcode to look up: UPC-A (12), EAN-13 (13), EAN-8 (8), GTIN-14, or ISBN-13 (978/979…). Spaces/dashes are stripped; check digit is validated (mod-10). Aliases: upc, ean, gtin, isbn, code.
- `source` (enum, optional, default "auto") — Which open source(s) to query for lookup/batch. 'auto' merges both. [one of: auto, off, upcitemdb]
- `off_db` (enum, optional, default "food") — Which Open-*-Facts sibling DB to search/lookup against when source=off. lookup auto-falls-back food→products when source=auto. [one of: food, beauty, petfood, products]

**Returns:** product{barcode, gtin13, gtin_type, valid_check_digit, issuing_country, title, brand, category, description, image, images[], nutrition{} (if food), ingredients, allergens[], offers[] (merchant/price), price_lowest/highest, sources[], field_source{}}

**Example request body:**
```json
{
  "barcode": "5449000000996"
}
```

### POST /barcode/v1/batch — 1 credit
Up to 20 barcodes in one call → array of merged products (input order preserved), each with its own source/validation. The competitor caps at 10.

**Parameters:**
- `barcodes` (array, required) — Up to 20 barcodes — a JSON array or a comma-separated string (competitor caps batch at 10; we allow 20). Each is normalized + validated; results preserve input order with per-item source.
- `source` (enum, optional, default "auto") — Which open source(s) to query for lookup/batch. 'auto' merges both. [one of: auto, off, upcitemdb]
- `off_db` (enum, optional, default "food") — Which Open-*-Facts sibling DB to search/lookup against when source=off. lookup auto-falls-back food→products when source=auto. [one of: food, beauty, petfood, products]

**Returns:** products[] (one per input barcode: found bool + merged product or not-found), requested, found_count

**Example request body:**
```json
{
  "barcodes": "5449000000996,0885909950805"
}
```

### POST /barcode/v1/search — 1 credit
Free-text product-name search across the open databases → product cards with pagination. Optional category scope. (Competitor: keyword/title/category search.)

**Parameters:**
- `query` (string, required) — Free-text product-name keyword search (matches title across the open databases). Aliases: q, search, name, title.
- `category` (string, optional) — Optional Open-Food-Facts category tag to scope a search/brand query (e.g. 'sodas', 'chocolate-spreads', 'biscuits').
- `off_db` (enum, optional, default "food") — Which Open-*-Facts sibling DB to search/lookup against when source=off. lookup auto-falls-back food→products when source=auto. [one of: food, beauty, petfood, products]
- `source` (enum, optional, default "auto") — Which open source(s) to query for lookup/batch. 'auto' merges both. [one of: auto, off, upcitemdb]
- `page` (integer, optional, default 1) — 1-based page number (clamped 1-1000). Page forward with meta.next_page. Note: Open Food Facts throttles deep pages per-IP; the engine retries on a fresh proxy.
- `page_size` (integer, optional, default 20) — Results per page (1-50, default 20); out-of-range values are clamped.

**Returns:** products[] (barcode, title, brand, category, image, nutriscore), count, page, page_count, has_more, next_page

**Example request body:**
```json
{
  "query": "nutella"
}
```

### POST /barcode/v1/by_brand — 1 credit
All products for a brand/manufacturer → product cards with pagination. (Competitor: brand + manufacturer search.)

**Parameters:**
- `brand` (string, required) — Brand or manufacturer name → that brand's products. Aliases: manufacturer, brand_name.
- `category` (string, optional) — Optional Open-Food-Facts category tag to scope a search/brand query (e.g. 'sodas', 'chocolate-spreads', 'biscuits').
- `off_db` (enum, optional, default "food") — Which Open-*-Facts sibling DB to search/lookup against when source=off. lookup auto-falls-back food→products when source=auto. [one of: food, beauty, petfood, products]
- `page` (integer, optional, default 1) — 1-based page number (clamped 1-1000). Page forward with meta.next_page. Note: Open Food Facts throttles deep pages per-IP; the engine retries on a fresh proxy.
- `page_size` (integer, optional, default 20) — Results per page (1-50, default 20); out-of-range values are clamped.

**Returns:** products[] (this brand's items), brand, count, page, page_count, has_more, next_page

**Example request body:**
```json
{
  "brand": "coca-cola"
}
```

### POST /barcode/v1/by_prefix — 1 credit
GS1 company-prefix (partial-barcode) search → products whose barcode starts with the given 6+ digits, plus the decoded issuing country. (Competitor: `491234*` partial method.)

**Parameters:**
- `prefix` (string, required) — A GS1 company prefix — the first 6+ digits of a barcode (the competitor's `491234*` partial-barcode method). Returns products whose barcode starts with these digits + the decoded issuing country.
- `off_db` (enum, optional, default "food") — Which Open-*-Facts sibling DB to search/lookup against when source=off. lookup auto-falls-back food→products when source=auto. [one of: food, beauty, petfood, products]
- `page` (integer, optional, default 1) — 1-based page number (clamped 1-1000). Page forward with meta.next_page. Note: Open Food Facts throttles deep pages per-IP; the engine retries on a fresh proxy.
- `page_size` (integer, optional, default 20) — Results per page (1-50, default 20); out-of-range values are clamped.

**Returns:** products[] (barcode starts-with prefix), prefix, issuing_country, count, page, has_more, next_page

**Example request body:**
```json
{
  "prefix": "5449000"
}
```

### POST /barcode/v1/by_mpn — 1 credit
Manufacturer-Part-Number / model lookup → products with that MPN/model (UPCitemdb keyword index over the MPN). Exact model/mpn matches are surfaced first. Closes the competitor's mpn query-method (the proprietary mpn= DB-index isn't on the open tier, but the keyword index resolves real MPNs — Logitech 910-005565, Sony WH-1000XM4, Canon 2727C002 all verified).

**Parameters:**
- `mpn` (string, required) — Manufacturer Part Number / model number → matching products. Aliases: model, model_number, part_number. Results whose model/mpn field equals the query are surfaced first (exact_match=true).
- `page` (integer, optional, default 1) — 1-based page number (clamped 1-1000). Page forward with meta.next_page. Note: Open Food Facts throttles deep pages per-IP; the engine retries on a fresh proxy.
- `page_size` (integer, optional, default 20) — Results per page (1-50, default 20); out-of-range values are clamped.

**Returns:** products[] (exact-mpn first, each w/ matched_mpn + exact_match bool), mpn, exact_match_count, count, page, page_count, has_more, next_page

**Example request body:**
```json
{
  "mpn": "910-005565"
}
```

### POST /barcode/v1/validate — 0 credits
Validate + decode a barcode WITHOUT a network call: mod-10 check digit, GTIN type, GTIN-13 normalization, GS1 issuing country, ISBN/Bookland detection. (We EXCEED the competitor here — it has no standalone validate.)

**Parameters:**
- `barcode` (string, required) — The barcode to look up: UPC-A (12), EAN-13 (13), EAN-8 (8), GTIN-14, or ISBN-13 (978/979…). Spaces/dashes are stripped; check digit is validated (mod-10). Aliases: upc, ean, gtin, isbn, code.

**Returns:** valid, gtin_type, digits, gtin13, check_digit, expected_check_digit, issuing_country, is_isbn, reason (if invalid)

**Example request body:**
```json
{
  "barcode": "5449000000996"
}
```

## More
- Try it live, no code: https://reefapi.com/playground?engine=barcode
- Human docs page: https://reefapi.com/docs/barcode
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
