From the digits under the bars to a product record, and what to do when a code is wrong, shared or missing.
Published
A barcode lookup API takes the number printed under a product’s barcode and returns the product it belongs to: name, brand, category, images and the other identifiers it is known by. Some APIs stop there; others also return current prices from retailers and price history for the same product.
Two products by UPC in one request (ShopSavvy Data API):
curl "https://api.shopsavvy.com/v1/products?ids=611247373064,611247369449" \
-H "Authorization: Bearer $SHOPSAVVY_API_KEY"A lookup costs 1 credit per product found. Codes that match nothing are left out of the response and cost nothing, and if nothing in the request matches at all, the API answers ERR_PRODUCT_NOT_FOUND so your app can fall back to manual entry. The catalog behind it holds 30M+ products.
| Format | Digits | Where you see it |
|---|---|---|
| UPC-A | 12 | Most products sold in the US and Canada |
| EAN-13 | 13 | Most of the rest of the world; a UPC-A with a 0 in front is the same code |
| ISBN-13 | 13 (starts 978 or 979) | Books |
| UPC-E / EAN-8 | 8 | Small packages; a UPC-E is a compressed UPC-A |
| GTIN-14 | 14 | Shipping cases; a leading 0 means the same item as the 13 digits after it |
Normalize before you send: strip spaces and dashes, keep codes as strings (a numeric type drops the leading zeros a UPC often starts with), and expand UPC-E to its UPC-A form if your catalog stores the long form. In ShopSavvy responses the barcode field is a number, so pad it back to 12 or 13 digits before you compare or display it.
The last digit of every UPC and EAN is computed from the others, so most typos and misreads can be caught before you spend a request. Any single wrong digit breaks the check, and so do most pairs of neighboring digits swapped.
// True when the last digit of a UPC-A, EAN-13, EAN-8 or GTIN-14 matches the others.
// Starting next to the check digit, every other digit counts 3 times.
function checkDigitValid(code: string): boolean {
const digits = code.replace(/[\s-]/g, '')
if (!/^(\d{8}|\d{12}|\d{13}|\d{14})$/.test(digits)) return false
const body = digits.slice(0, -1).split('').reverse().map(Number)
const sum = body.reduce((total, digit, index) => total + digit * (index % 2 === 0 ? 3 : 1), 0)
return (10 - (sum % 10)) % 10 === Number(digits[digits.length - 1])
}In the ShopSavvy Data API, every identifier in ids is tried against these fields in order, and the first field that matches wins:
Every product in the response carries a match object that says how it was found:
"match": { "identifier": "611247373064", "by": "barcode", "candidates": 1 }candidates above 1 means the code is shared by several catalog records, usually because a manufacturer reused it or a retailer listed the item twice. The API then returns the record with the most evidence behind it (the most verified offers on file), and the same one every time. Flag those results for a person to confirm if a wrong match would be costly.
A lookup tells you what a product is. To see what it costs, call the offers endpoint with the same code: offers from tens of thousands of retailers, each with its price, condition, availability, link and the time it was seen (3 credits per product that has offers). Add a date window for price history.
Free UPC lookup → Checking one code by hand? The free lookup shows the product, brand, category and photo with no account.
Yes. shopsavvy.com/tools/upc-lookup looks up one barcode at a time with no account, within per-visitor limits. For lookups from your own code or in bulk, use the Data API.
Some do. With ShopSavvy, the product endpoint returns the product record and the offers endpoint returns current prices from retailers for the same barcode, with price history available by date window.
Codes that match nothing are left out of the response and cost nothing. If no code in the request matches, the API returns ERR_PRODUCT_NOT_FOUND, so your app can ask for the product another way.
Yes, by ISBN-13, the 13-digit number starting with 978 or 979 that is printed under a book’s barcode.