Skip to main content

Product metadata reference

This is the complete field-by-field reference for the structured metadata returned by GET /api/v1/products/{barcode}. Every field has:

  • Type — JSON type + underlying storage type
  • Presence — always populated / optional / null when not applicable
  • Semantic meaning — what the field actually represents, not just what it's called
  • Real example — copied from live catalog data, not made-up
note

Metadata is split into two independent scopes: image_meta (facts about the physical image files — dates, resolution, ownership) and product_meta (facts about the product itself — brand, ingredients, hechshers, nutrition). Request either or both via ?include=. See Filtering the response below.


Full response — real example

Live catalog entry for barcode 000413000222 (Example Brand Fish Sticks):

{
"barcode": "000413000222",
"image_meta": {
"front": {
"photo_date": "2023-10-19",
"upload_date": "2026-04-26 04:33:40",
"resolution": "1000x1000",
"ownership": "Studio A",
"uploaded_by": "Photographer 1",
"file_size_bytes": 184521,
"source_batch": "zip_upload"
},
"back": {
"photo_date": "2023-10-19",
"upload_date": "2026-04-26 04:33:40",
"resolution": "1000x1000",
"ownership": "Studio A",
"uploaded_by": "Photographer 1",
"file_size_bytes": 201338,
"source_batch": "zip_upload"
},
"front_clean": {
"photo_date": "2023-10-19",
"upload_date": "2026-04-26 05:43:03",
"resolution": "1000x1000",
"ownership": "Studio A",
"uploaded_by": "Photographer 1",
"file_size_bytes": 942016,
"source_batch": "zip_upload"
},
"back_clean": {
"photo_date": "2023-10-19",
"upload_date": "2026-04-26 05:43:03",
"resolution": "1000x1000",
"ownership": "Studio A",
"uploaded_by": "Photographer 1",
"file_size_bytes": 876412,
"source_batch": "zip_upload"
}
},
"product_meta": {
"brand": "Example Brand",
"product_name": "Example Brand Fish Sticks — Sample Product",
"product_description": "Made from 100% Fish Fillets, Premium Product with No Fillers",
"net_weight": "Net Wt 20 oz (1 lb 4 oz / 567 g)",
"category": "frozen",
"country_of_origin": "United States",
"manufacturer": "Manufactured for ACME Foods LLC, Anytown USA",
"distributor": "ACME Foods LLC, Anytown USA — contact@acmefoods.example — www.acmefoods.example",
"additional_certifications": "MSC Certified Sustainable Seafood",
"bracha": "shehakol",
"kosher_for_passover": false,
"gluten_free": false,
"vegan": false,
"organic": false,
"hechshers": [
{
"symbol": "OK",
"org": "OK Kosher Certification (per Example Brand brand standard)",
"logo": "ok.png",
"dairy_meat_pareve": "pareve",
"additional_designation": null
}
],
"ingredients": {
"ingredients_text": "Pollock, Enriched Bleached Wheat Flour (flour, niacin, ferrous sulfate, thiamine mononitrate, riboflavin, folic acid), Water, Soybean Oil, Modified Corn Starch, Yellow Corn Flour, Contains 2% or Less of: Sugar, Salt, Dextrose, Leavening (monocalcium phosphate, sodium bicarbonate), Yeast, Yeast Extract, Modified Cellulose, Onion Powder.",
"contains_statement": "Contains: Fish (Pollock), Wheat.",
"may_contain_statement": "Contains Bioengineered Food Ingredients. From an MSC certified sustainable fishery. Keep frozen.",
"allergens": ["fish", "wheat"]
},
"nutrition": {
"servings_per_container": "About 5",
"serving_size": "4 sticks (112g)",
"calories": "230",
"total_fat": {"amount": "8g", "dv": "10%"},
"saturated_fat": {"amount": "1g", "dv": "6%"},
"trans_fat": {"amount": "0g", "dv": null},
"cholesterol": {"amount": "35mg", "dv": "12%"},
"sodium": {"amount": "390mg","dv": "17%"},
"total_carbohydrate": {"amount": "28g", "dv": "10%"},
"dietary_fiber": {"amount": "<1g", "dv": "3%"},
"total_sugars": {"amount": "1g", "dv": null},
"added_sugars": {"amount": "1g", "dv": "2%"},
"protein": {"amount": "13g", "dv": null},
"vitamin_d": {"amount": "1mcg", "dv": "6%"},
"calcium": {"amount": "40mg", "dv": "4%"},
"iron": {"amount": "2.1mg","dv": "10%"},
"potassium": {"amount": "230mg","dv": "4%"}
},
"notes": "Example Brand Fish Sticks — 20 oz / 567g cardboard box with blue wood-plank background. Made from 100% Pollock fish fillets...",
"scanned_at": "2026-05-06 23:24:30",
"updated_at": "2026-06-22 09:54:07"
},
"images": {
"front": "https://images.retaildigitals.com/api/v1/image/eyJi...(base64url).(HMAC)",
"back": "https://images.retaildigitals.com/api/v1/image/eyJi...",
"front_clean": "https://images.retaildigitals.com/api/v1/image/eyJi...",
"back_clean": "https://images.retaildigitals.com/api/v1/image/eyJi..."
},
"meta": {
"request_id": "req_01H8Y3G7Z8mnpqrsw",
"credits_debited": 4.6,
"credits_remaining": 4321.8,
"response_generated": "2026-07-01T20:52:14Z"
}
}

Response envelope

The top level always contains:

FieldTypePresenceDescription
barcodestringAlwaysEcho of the barcode you requested. Normalized (leading zeros preserved).
image_metaobject | nullOnly if ?include= includes image_meta (default)Per-variant image facts. See image_meta below.
product_metaobject | nullOnly if ?include= includes product_meta (default)Product-level facts: brand, ingredients, hechshers, nutrition. See product_meta below.
imagesobject | nullOnly if ?include= includes images (default)Signed URLs for each available variant. See images below.
metaobjectAlwaysPer-request metadata: request_id, credits debited, credits remaining.

image_meta — physical file facts

Contains one entry per variant. Variants that don't exist for this barcode are null, not omitted — so client code can always destructure image_meta.front, image_meta.back, etc. without checking for undefined keys.

"image_meta": {
"front": { ... } | null,
"back": { ... } | null,
"front_clean": { ... } | null,
"back_clean": { ... } | null
}

Each variant that exists is an object with the following fields:

FieldTypePresenceDescription
photo_datestring (YYYY-MM-DD)AlwaysThe date the shutter fired (from EXIF DateTimeOriginal when the raw file was captured). Some legacy entries may only have day-precision.
upload_datestring (YYYY-MM-DD HH:MM:SS)AlwaysWhen the file landed on our server. Timezone: server-local (UTC-4). Use this if you're building a "recently updated" filter.
resolutionstring ({width}x{height})AlwaysPixel dimensions, e.g. "1000x1000". Nearly all current-generation images are 1000×1000; some legacy is smaller.
ownershipstringUsuallyThe photographer / batch tag assigned when the image was imported. Common values: "Studio A", "Studio B", brand-specific tags.
uploaded_bystring | nullUsuallyThe admin user who ran the import job. Useful for internal audit; not typically consumer-relevant.
file_size_bytesintegerAlwaysByte size of the actual JPG or PNG file on disk. JPGs are ~50–200 KB; PNGs are ~600 KB–1 MB.
source_batchstringAlwaysHow this row got created. One of: "zip_upload", "review_approved", "png_variant_orphan_repair_2026-05-13", "restore_missing_front_2026-05-19", occasionally other one-off migration batches.

Variant naming

VariantMeaningFile format
frontFront of the product, white background — studio shotJPG
backBack of the product (usually nutrition + ingredients panel), white backgroundJPG
front_cleanFront of the product, transparent background — background removed via InSPyReNet pipelinePNG
back_cleanBack of the product, transparent backgroundPNG

Availability patterns to expect:

  • Most products have front + front_clean (~91% of catalog)
  • Fewer products also have back + back_clean (~46% of catalog)
  • A small minority (~200 products) have only back-side images (usually work-in-progress ingest)
  • No product has fewer than one variant — an entry with zero images doesn't exist in the catalog

product_meta — the product itself

This is the "structured metadata" section — everything you'd need to render a professional product page without hosting anything yourself.

Identity & positioning

FieldTypePresenceDescription
brandstring | nullUsuallyManufacturer or brand as it appears on the package. Examples: "Example Brand", "Sample Foods", "Sample Distributor". Non-food items may lack this.
product_namestring | nullUsuallyFull product name as shown on the front of package. May include descriptive suffixes (e.g. "Fish Stix — Made from 100% Fish Fillets").
product_descriptionstring | nullOptionalMarketing sub-tagline from the front of pack (e.g. "Premium Product with No Fillers"). Often blank.
net_weightstring | nullUsuallyNet weight with unit as printed. Free-text, not a normalized number — examples: "Net Wt 20 oz (1 lb 4 oz / 567 g)", "350 mL", "12 pack x 355 ml". If you need a canonical weight, parse client-side.
categorystring | nullUsuallyBroad grouping. Examples: "cereal", "frozen", "beverages", "dairy", "produce", "judaica", "snacks". Not a strict enum — new categories appear as new items are scanned. See Category values below for current distribution.
country_of_originstring | nullUsuallyCountry where the product was manufactured. Examples: "United States", "Israel", "Canada", "Belgium".

Commercial info

FieldTypePresenceDescription
manufacturerstring | nullOptionalManufacturer name + address as printed. Full sentence form: "Manufactured for ACME Foods LLC, Anytown USA".
distributorstring | nullOptionalDistributor name + address + contact. Full sentence: "ACME Foods LLC, Anytown USA — contact@acmefoods.example — www.acmefoods.example".
additional_certificationsstring | nullOptionalNon-kosher certifications: "USDA Organic", "MSC Certified Sustainable Seafood", "Non-GMO Project Verified", "Fair Trade Certified". Comma-separated free text.

Kosher classification

FieldTypePresenceDescription
brachastring | nullUsually (food items)The Hebrew blessing category for this product. Enum of Hebrew brachot; see Bracha values below.
kosher_for_passoverbooleanAlwaystrue if the product is marked kosher for Passover, else false. Non-food items are always false.
hechshersarrayAlways (may be empty)Kosher certification stamps on the package. May be 0 items (non-kosher-labeled or non-food), 1 item (most common), or multiple (products certified by multiple agencies). Each element documented in hechsher object below.

Dietary flags

FieldTypePresenceDescription
gluten_freebooleanAlwaystrue only if the package explicitly claims gluten-free.
veganbooleanAlwaystrue only if the package explicitly claims vegan / plant-based.
organicbooleanAlwaystrue only if certified organic (USDA, EU, etc.). Best-effort.
tip

These flags are conservative — they're true only when the package explicitly claims the certification. A vegan-in-practice product without a vegan certification will still return vegan: false. If you want to build filters like "no dairy", combine vegan: true OR hechshers[].dairy_meat_pareve == "pareve" OR ingredient text scanning.

hechsher object

Each element of hechshers[]:

FieldTypePresenceDescription
symbolstringAlwaysShort abbreviation as the agency uses it. Examples: "OU", "OK", "Star-K", "CRC", "Chof-K", "Kof-K", "Badatz Eda HaChareidis", "NSK / Skverer". See Common hechsher symbols for the full list.
orgstring | nullUsuallyFull organization name. Example: "Orthodox Union" for "OU", "OK Kosher Certification" for "OK". May include a disambiguating suffix ("OK Kosher Certification (per Example Brand brand standard)") when the same symbol is used by multiple agencies.
logostring | nullUsuallyLogo image filename. Currently: "ou.png", "ok.png", "star-k.png", etc. (relative to our logo asset store; not currently exposed as a signed URL — v2).
dairy_meat_parevestring | nullUsuallyOne of: "dairy", "meat", "pareve". If the certification doesn't specify, this is null (rare).
additional_designationstring | nullOptionalFree-text additional labels the agency applies. Common values: "Cholov Yisroel", "Pas Yisroel", "Yoshon", "Bishul Yisroel", "Non-Gebrokts", "Kosher for Passover", or a combination like "Pas Yisroel, Yoshon".
note

A product can have multiple hechshers. Some products carry both a primary certification (e.g. OU) and a supplementary Pas Yisroel supervision from a separate Rav. The hechshers[] array preserves this — don't assume it's always a single entry.

Ingredients

Nested object under product_meta.ingredients:

FieldTypePresenceDescription
ingredients_textstring | nullUsually (food)Full ingredients list, comma-separated, as printed. Preserves parenthetical sub-ingredients and their nested enrichments. Empty string for non-food items.
contains_statementstring | nullOptionalThe bold FDA-style Contains: line. Example: "Contains: Fish (Pollock), Wheat."
may_contain_statementstring | nullOptionalMay-contain / advisory statements + other footnotes. Often includes bioengineered-food disclosures, MSC certification notes, storage instructions. Example: "Contains Bioengineered Food Ingredients. From an MSC certified sustainable fishery. Keep frozen."
allergensarray of stringAlwaysNormalized allergen list. Common values: "milk", "eggs", "fish", "shellfish", "tree nuts", "peanuts", "wheat", "soy", "sesame". Derived from contains_statement; explicit list makes filtering easy. Empty array [] if no allergens.

nutrition — the facts panel

Nested object under product_meta.nutrition. Present for food items with a nutrition facts panel; null for non-food. All numeric values are strings (as printed on package — e.g. "<1g", "About 5") so we preserve exact package language.

Serving info

FieldTypeDescription
servings_per_containerstring | nullAs printed. "About 5", "2", "5.5", "Varies".
serving_sizestring | nullAs printed. "4 sticks (112g)", "1 cup (240 mL)", "3 pieces (30g)".
caloriesstring | nullNumeric string. "230", "90", "0".

Macronutrients

Each of these is an object { amount, dv } where amount is the printed quantity (e.g. "8g") and dv is the printed % Daily Value (e.g. "10%"), or null if not shown on package.

FieldTypeExample
total_fat{amount, dv}{"amount": "8g", "dv": "10%"}
saturated_fat{amount, dv}{"amount": "1g", "dv": "6%"}
trans_fat{amount, dv}{"amount": "0g", "dv": null} — trans fat rarely has DV printed
cholesterol{amount, dv}{"amount": "35mg", "dv": "12%"}
sodium{amount, dv}{"amount": "390mg", "dv": "17%"}
total_carbohydrate{amount, dv}{"amount": "28g", "dv": "10%"}
dietary_fiber{amount, dv}{"amount": "<1g", "dv": "3%"}
total_sugars{amount, dv}{"amount": "1g", "dv": null} — total sugars usually has no DV
added_sugars{amount, dv}{"amount": "1g", "dv": "2%"}
protein{amount, dv}{"amount": "13g", "dv": null} — protein usually no DV on US labels

Micronutrients

FieldTypeExample
vitamin_d{amount, dv}{"amount": "1mcg", "dv": "6%"}
calcium{amount, dv}{"amount": "40mg", "dv": "4%"}
iron{amount, dv}{"amount": "2.1mg", "dv": "10%"}
potassium{amount, dv}{"amount": "230mg", "dv": "4%"}
tip

Why strings, not numbers? Because packages print things like "<1g", "less than 1%", "Varies", "About 5", "25*" (asterisks referring to footnotes). We preserve the printed form so consumers can render it verbatim; if you need normalized numbers, parse client-side (parseInt / regex extraction).

Notes & timestamps

FieldTypePresenceDescription
notesstring | nullUsuallyFree-form catalog notes from the scanner — packaging description, Hebrew label transcription, kashrus quirks, sourcing notes. Great for internal reference; not typically shown to end consumers.
scanned_atstring ISOAlwaysWhen the initial product record was created (first scan / import).
updated_atstring ISOAlwaysWhen any field of product_meta was last modified. Use this as a cache invalidation signal.

images — signed URLs

Object with one signed URL per available variant. Variants that don't exist are null.

"images": {
"front": "https://images.retaildigitals.com/api/v1/image/eyJi...",
"back": "https://images.retaildigitals.com/api/v1/image/eyJi...",
"front_clean": "https://images.retaildigitals.com/api/v1/image/eyJi...",
"back_clean": null
}

Each URL:

  • Is signed with HMAC-SHA-256; can't be forged.
  • Expires in 15 minutes (default; configurable per client).
  • Is bound to your source IP at issuance — usable only from the same IP.
  • Is single-use — dies after first successful GET.
  • Delivers the image with correct Content-Type (image/jpeg or image/png).
  • Includes the global watermark + per-client traceable overlay (see Security → Watermarking).

See Image URL security for full details on the URL format and threat model.


meta — per-request info

Always present, tells the client what just happened:

FieldTypeDescription
request_idstringUnique ID for this request. Include in support tickets — we can look up the exact request in our audit log.
credits_debitednumberCredits charged for this specific call. Fractional (e.g. 2.6).
credits_remainingnumberYour balance after this call.
response_generatedstring ISOServer timestamp when the response was assembled.

Filtering the response

Use the include= query parameter to fetch only the metadata scopes you need, and the variants= parameter to fetch only the image variants you need. Reduces bytes over the wire and cost.

GET /api/v1/products/000413000222?include=image_meta,product_meta,images # default — all three scopes, all variants
GET /api/v1/products/000413000222?include=images # just images (all variants)
GET /api/v1/products/000413000222?include=product_meta # just product metadata
GET /api/v1/products/000413000222?include=product_meta,images # metadata + URLs, skip image_meta
GET /api/v1/products/000413000222?include=images&variants=front # only the front image URL
GET /api/v1/products/000413000222?include=images&variants=front,back # only front + back URLs

variants= accepted values: front, back, front_clean, back_clean — comma-separated. Requesting a variant that doesn't exist for this barcode returns null for that slot (no charge). Anything outside these four values returns 400 bad_request. Pricing is per requested variant, so variants=front on a 4-variant product costs 1 credit instead of 4.

The interaction of include= and variants=

Cost formula (see Pricing for the canonical explanation):

credits = (per_scope_rate × metadata_scopes_returned) + (per_image_rate × image_variants_returned)

include= controls the first term, variants= controls the second — they add up, they don't substitute. If you set only one, you still pay full price on the other. Both rates are admin-set — always look them up at GET /pricing.

The interaction matrix — combinations of include= and variants= and what each returns:

include=variants=Scopes billedImage URLs billedBest for
omitted (default)omitted (default)2 (product_meta, image_meta)N available (up to 4)Nothing — most expensive combination.
product_meta(ignored — no images)10Text-only sync: brand, ingredients, nutrition, hechshers.
image_meta(ignored — no image URLs)10Rarely useful alone; internal audits.
imagesomitted0N availableYou want every variant URL.
imagesfront01Single-image POS or PDP — cheapest way to get one image URL.
imagesfront,back02You render both sides.
product_meta,imagesfront11You render one image AND display ingredients / nutrition.
omittedfront2 (default)1⚠ Landmine — same metadata cost as omitting both, only image cost drops. Fix by also setting include=images.
anyvalue outside front / back / front_clean / back_clean00400 bad_request, nothing charged.

Worked example — one image URL only (cheapest single-image fetch):

GET /api/v1/products/000413000222?include=images&variants=front

Response contains only images.front; back, front_clean, back_clean come back as null. Cost = 1 × per_image_rate.

Worked example — text metadata plus one image (typical PDP fetch):

GET /api/v1/products/000413000222?include=product_meta,images&variants=front

Response contains product_meta and images.front. Cost = 1 × per_scope_rate + 1 × per_image_rate.

See Pricing for the full formula, cheapest-pattern ladder, and guidance on caching aggressively.


Reference tables

Bracha values

Current values seen in the catalog (all in Hebrew transliteration, lowercased):

  • "hamotzi" — bread from the five grains
  • "mezonos" — cakes, crackers, cereals from five grains
  • "hagafen" — wine and grape juice
  • "haetz" — fruit of the tree
  • "haadama" — fruit of the ground (vegetables, legumes)
  • "shehakol" — everything else (meat, fish, dairy, drinks, misc)
  • Empty string / null — non-food or unknown

Category values (top 20 by frequency)

Not a strict enum. Live distribution:

cereal, snacks, beverages, dairy, frozen, produce, meat, poultry, fish, bakery, candy, condiments, canned goods, pasta, oils, spices, soups, juice, judaica, paper goods, and dozens of long-tail categories. Treat as free-form for filtering.

Common hechsher symbols

The most common values you'll see in hechshers[].symbol. This is not exhaustive — the catalog has ~80 distinct hechsher agencies.

SymbolFull name
OUOrthodox Union
OKOK Kosher Certification
Star-KStar-K Kosher Certification
Star-DStar-D (dairy division of Star-K)
CRCChicago Rabbinical Council (also see disambiguation for "(CRC)" Hitachdus)
Chof-KChof-K Kosher Supervision
Kof-KKof-K Kosher Supervision
KSAKosher Supervision of America
KVHKosher Va'ad Harabonim of New England
Badatz Eda HaChareidisBadatz Eda HaChareidis (Jerusalem)
Badatz Beit YosefBadatz Beit Yosef
NirbatorNirbator Rav (chassidic)
NSK / SkvererNew Square Kashrus (Skverer Beis Din)
Tartikov KashrusTartikov Kashrus
CORKashruth Council of Canada
Hisachdus HoRabbonimHisachdus HoRabbonim (see disambiguation for CRC)
Many more...Long tail of regional / chassidic / small-agency hechshers

dairy_meat_pareve values

"dairy" · "meat" · "pareve" · null (if hechsher doesn't specify)

allergens values

Normalized snake-case strings. Common values:

"milk", "eggs", "fish", "shellfish", "tree nuts", "peanuts", "wheat", "soy", "sesame", "sulfites", "gluten" (used interchangeably with "wheat" for products whose statement uses "gluten"), "crustacean shellfish", "mollusks", "lupin", "mustard", "celery".

Always an array (possibly empty). Never null.


Data quality guarantees

Field groupGuarantee
barcode, image_meta.* (for existing variants)Always populated for any product returned by the API — these are the primary keys.
brand, product_name, category, country_of_origin, brachaPopulated for ~92% of food items, ~40% of non-food. Best-effort scanned from packaging. Non-food items (Judaica, cleaning, paper goods) often lack bracha.
hechshers, ingredients, nutritionPopulated for ~85% of food items. Non-food is null / empty. New scans are populated for 100% of new food items.
net_weight, manufacturer, distributor, notesBest-effort. Populated when clearly visible on the package.
additional_certificationsPopulated only when explicit certification marks exist on package.

Freshness: the updated_at field on product_meta reflects the last edit. On average, ~200 products are updated per week (new scans + corrections).


Common pitfalls

Assuming hechshers is always a single item

Some products carry multiple hechshers (primary + Pas Yisroel supervision, for example). Iterate — don't index hechshers[0] and assume that's the whole story.

// ❌ Don't
const cert = product.product_meta.hechshers[0].symbol;

// ✅ Do
const certs = product.product_meta.hechshers.map(h => h.symbol).join(', ');
Treating nutrition values as numbers

"<1g", "About 5", "Varies" are all valid values. If you need numbers, parse:

function extractGrams(str) {
if (!str) return null;
const m = str.match(/(\d+(?:\.\d+)?)\s*g/i);
return m ? parseFloat(m[1]) : null;
}
extractGrams("<1g"); // null (intentional — <1 isn't a specific number)
extractGrams("8g"); // 8
extractGrams("2.1mg"); // null (units mismatch, won't match /g/)
Assuming vegan: false means the product contains animal products

Our vegan flag is conservative — only true when the package explicitly claims vegan certification. Many products that are vegan-in-practice (pareve candy, plant-based crackers) will still return vegan: false. If you need "no animal ingredients", also check hechshers[].dairy_meat_pareve == "pareve" and scan the ingredients text.

Signed image URL returns 410 Gone on second load

Signed URLs are single-use. Perfect for <img src> where the browser fetches once, but bad if your CDN or reverse proxy re-requests the URL. Options:

  1. Fetch the image server-side, cache the bytes, re-serve to browsers
  2. Disable one-shot for your client_id (Enterprise tier only)
  3. Fetch a fresh signed URL each time you serve the product
Bracha field is empty for a food product

Some legacy scans predate the bracha classification workflow. Modern scans always populate it. If a critical use case depends on bracha, filter by !!product_meta.bracha before using.