BevFacts
Developer API

Put a nutrition label
on every order

Compute Dynamic Beverage Nutrition Facts for the exact drink a customer ordered β€” from your POS, kiosk, or ordering app. Fully integrated with Foodlang and ORF, so an executable recipe and its label share one source. The engine runs in the browser today; a hosted REST API is on the way.

What you can build

One engine, six integration surfaces

⚑

In-browser JS engine Live

Drop in engine.js and call window.BevFacts β€” compute, round, declare, and render labels with zero network calls.

🍳

Foodlang & ORF Live

Parse any Foodlang .food drink into a label, and export drinks as ORF-style .food.yaml. Details below ↓

πŸ”—

URL deep links Live

Encode a whole drink into a shareable link or QR code. Scannable by any phone, resolvable with no backend.

πŸ›°οΈ

REST API Draft

Compute and persist labels server-side, render PNG/SVG, and pull vendor recipe tables over HTTP.

πŸ””

Webhooks Draft

Subscribe to cup.returned and label.created events with signed, replay-protected payloads.

πŸ—„οΈ

Open recipe data Draft

Publish and consume base recipes, milks, syrups, and toppings as machine-readable JSON.

Quickstart

Compute a label in three lines

The engine is a single static file with no dependencies. Everything below runs on this very page β€” open your console and try it.

<script src="engine.js"></script>
<script>
  // Base recipe + the modifiers the customer ordered
  const order = {
    drinkName: "Caramel Latte",
    calories: 250, sugars: 33, addedSugars: 28, caffeine: 150,
    totalFat: 7, satFat: 4.5, sodium: 170, totalCarb: 35, protein: 10,
    sweetness: 100, pumps: 3, shots: 2          // +3 syrup pumps, +2 espresso shots
  };

  const facts    = BevFacts.compute(order);     // unrounded, as-ordered
  const declared = BevFacts.declare(facts);     // 21 CFR 101.9 rounded strings
  const warnings = BevFacts.warnings(facts);    // e.g. ["added_sugars_over_100pct_dv"]
  const link     = BevFacts.link(order);        // shareable deep link / QR target
</script>

Live playground

Run the engine now

Edit the order JSON and press Run. This calls the real window.BevFacts API loaded on this page β€” the same code your integration would ship.

Order (JSON)

Result


        

Rendered label

Reference

The window.BevFacts API

MemberSignatureReturns
versionstringSpec version, e.g. "1.0-draft"
DVobjectDaily-value table (added sugars 50, sodium 2300, …)
PRESETSarrayExample base recipes
compute(order)(state) β†’ nutrientsUnrounded as-ordered vector (sweetness, pumps, shots applied)
declare(nutrients)(nutrients) β†’ stringsFDA-rounded declaration strings + %DV
warnings(nutrients)(nutrients) β†’ string[]Machine-readable warning flags
round{calories, fat, …}The individual 21 CFR 101.9 rounding functions
labelHTML(order)(state) β†’ stringInner HTML of a ready-to-style Nutrition Facts label (add qr:true for a scannable QR)
labelSVG(order)(state) β†’ stringA standalone, print/PNG-ready SVG label (no foreignObject)
encodeState / decodeState(obj) ⇄ (string)Compact URL-fragment codec (short keys, defaults omitted)
link(order)(state) β†’ stringA deep-link URL encoding the whole order (the QR target)
foodlang{parse, estimate, toFood, toORF, fromRecipe}The Foodlang/ORF bridge β€” see below
pdf{singleLabel, sheet}FreshPDF (freshpdf.com) β€” build a real PDF from rasterized label images, in-browser

Integrations

Fully integrated with Foodlang & ORF

BevFacts is the nutrition layer for Foodlang β€” the ORF-compatible executable-recipe language. A .food drink compiles to coffee machines, robots, and the web; BevFacts makes the same source compile to a Nutrition Facts label.

🍳

.food β†’ label

Paste any Foodlang drink into the generator (or call BevFacts.foodlang.parse + estimate) and its ingredients are costed against the DBNF reference tables into a full label. Unmatched ingredients are reported, never silently guessed β€” same honesty rule as Foodlang's fidelity grades.

πŸ“€

Label β†’ .food / ORF

Export any recipe-builder drink as a .food document (ingredients + phases) or as ORF-style .food.yaml with X-Phases and an X-Nutrition block carrying the DBNF values β€” the X- prefix per the ORF extension convention.

// the foodlang.com homepage example, straight into a label
const rec = BevFacts.foodlang.parse(`drink "Iced Vanilla Latte" {
  ingredients { coffee 18 g; vanilla_syrup 20 ml; milk 10 oz; ice 140 g }
}`);
const { state, unmatched } = BevFacts.foodlang.estimate(rec);
document.body.innerHTML = BevFacts.labelHTML(state);   // 144mg caffeine, 24g sugar…

// and back out: recipe-builder drink β†’ ORF-style .food.yaml
const food = BevFacts.foodlang.fromRecipe({ base: "latte", milk: "oat", pumps: 3, syrup: "flavor" }, BevFacts);
BevFacts.foodlang.toORF(food, state, BevFacts);        // recipe_name / X-Phases / X-Nutrition

Draft Β· hosted API

REST for server-side integrations

The wire format is specified and stable enough to build against; endpoints are not yet hosted. Full details β€” auth, idempotency, pagination, webhooks, and errors β€” live in Part 5 of the spec.

EndpointPurpose
POST /v1/labelsCompute & optionally render a label (PNG / SVG / JSON)
GET /v1/labels/{id}Retrieve a computed label document by id or hash
GET /v1/presetsList a vendor's published base recipes
GET /v1/cups/{id}Deposit / return state for a reusable cup
POST /v1/cups/{id}/returnRecord a return scan; emit cup.returned
curl https://api.bevfacts.example/v1/labels \
  -H "Authorization: Bearer bf_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "drink": { "name": "Caramel Latte", "servingSize": { "amount": 16, "unit": "fl_oz", "ml": 473 } },
        "base": { "calories": 250, "sugars_g": 33, "addedSugars_g": 28, "caffeine_mg": 150 },
        "modifiers": [ { "type": "syrup_pump", "count": 3 }, { "type": "espresso_shot", "count": 2 } ],
        "render": ["png", "json"] }'

Want the hosted API, webhooks, or an SDK for your stack?

The REST surface, event signatures, and cup-return lifecycle are specified in the open. Follow along or weigh in via GitHub, or read the full API specification.