Skip to content
Recipe API

The Meal Kit Has Three Truths: Recipe, Box, and Delivery

A component array can describe what a meal kit contains, but reliable nutrition, substitutions, and support require separate records for the recipe specification, sellable box, and fulfilled delivery.

recipe-datameal-planninggrocerynutritionapi-design

A components array opens the right door

An open Open Food Facts pull request, created September 5, proposes API v3 support for a components array. The motivating case is one barcode covering several distinct foods with separate ingredient lists or nutrition panels: a vegetable plus a sauce sachet, a lunch kit, or a variety pack. The underlying issue gives a precise example: Brussels sprouts and a butter-oil glaze share one package, but users can consume the sprouts and discard the glaze. Combining both nutrition columns produces a mathematically defensible number for a meal nobody necessarily ate.

That modeling problem becomes more consequential in meal kits. An NBC review published September 3 describes weekly recipe selection, protein and side swaps, pre-measured ingredients, recipe-labeled paper bags, and larger items such as meats and pasta packed outside those bags. Meanwhile, USA Today reported on August 31 that some Blue Apron and Marley Spoon customers received missing, incomplete, late, or spoiled deliveries during fulfillment-partner transitions. The companies described remedies including menu narrowing, extra quality checks, credits, refunds, and replacements.

These sources expose three different claims that a food API must not collapse:

  1. Recipe truth: what the cook is instructed to use.
  2. Box truth: what the sellable configuration promises to contain.
  3. Delivery truth: what was actually packed and received.

The thesis: model meal kits as a versioned reconciliation across recipe specification, commercial component manifest, and fulfillment observation; otherwise a technically correct component list will still produce incorrect nutrition, unsafe substitutions, broken instructions, and poor support decisions.

Why the recipe cannot be the box manifest

A recipe ingredient list describes culinary intent. A box manifest describes supplied inventory. They overlap, but they are not interchangeable.

A recipe may say “season with salt and oil” while the customer is expected to provide both. Several recipes may share one physical packet. A protein upgrade can change the supplied product, price, allergens, cooking step, and nutrition without changing the recipe’s public identity. Meat may travel outside the paper bag associated with the rest of a meal. A package may also include promotional samples or an ice pack that belong in logistics data, not recipe ingredients.

The distinctions become clearer in a table:

Question Recipe specification Box manifest Delivery observation
What does it represent? Culinary intent Promised sellable configuration A particular fulfillment attempt
Typical identity Recipe ID + revision Offer/SKU ID + revision Order, shipment, and delivery IDs
Quantity means Amount used Amount or pack promised Amount observed or reported
Nutrition means Expected prepared meal Labeled component or configured box Recalculated result if actual inputs are known
Missing means Recipe data is incomplete Item is customer-supplied or configuration is invalid Picking, packing, or delivery exception
Change mechanism Recipe revision Configuration/substitution revision Append-only event or claim

Putting all three into recipe.ingredients[] causes temporal errors. If a delivery is missing garlic, the canonical recipe did not stop containing garlic. If a warehouse substitutes chicken thighs for breasts, historical customers did not all receive thighs. If next week’s kit replaces one sauce, last week’s nutrition and allergen evidence must remain reproducible.

A compact three-layer model

A useful internal representation can link the layers without embedding them into one another:

{
  "recipeSpec": {
    "id": "recipe:lemon-chicken",
    "revision": 12,
    "servings": 2,
    "requirements": [
      {
        "id": "req:protein",
        "ingredientId": "ingredient:chicken-breast",
        "quantity": {"value": 280, "unit": "g"},
        "usedInSteps": [2, 4]
      }
    ]
  },
  "kitOffer": {
    "id": "offer:2026-w36-lemon-chicken",
    "revision": 4,
    "recipeRevision": 12,
    "components": [
      {
        "id": "component:protein",
        "fulfills": ["req:protein"],
        "supplyMode": "included",
        "productRef": "sku:chicken-280g",
        "declaredQuantity": {"value": 280, "unit": "g"},
        "nutritionPanelRef": "nutrition:panel-884",
        "substitutionPolicy": "approval_required"
      }
    ]
  },
  "fulfillment": {
    "shipmentId": "shipment:9012",
    "offerRevision": 4,
    "observations": [
      {
        "componentId": "component:protein",
        "status": "substituted",
        "actualProductRef": "sku:chicken-thigh-300g",
        "observedAt": "2026-09-06T18:42:00Z",
        "source": "warehouse_scan"
      }
    ]
  }
}

This is not a universal public schema. The important properties are stable references, explicit revisions, and directional links. The offer says which component fulfills which recipe requirement. The fulfillment record points to the exact offer revision it attempted to satisfy. An observed substitute does not overwrite either source object.

Components need semantics, not just nesting

Adding components[] solves a cardinality problem: one commercial identity can contain many foods. Production systems still need to define what each element means.

Give components stable IDs within a revision. Array positions are fragile. If sauce moves from position two to three, support claims and analytics should not silently follow the index.

Separate inclusion from requirement. Use values such as included, customer_supplied, optional_add_on, and shared_across_meals. An absent pantry staple is not a packing failure. An optional garnish should not block recipe completion.

Link rather than duplicate. A component can fulfill one or more recipe requirements. Keep the original recipe amount and the declared package amount. The difference supports waste estimates, scaling, and shortage detection without pretending “amount bought” equals “amount eaten.”

Version substitutions as configurations. A selectable protein swap is part of the commercial offer before checkout. A warehouse substitution is a fulfillment event after selection. Both require constraint checks, but they have different consent and pricing rules.

Attach nutrition to its basis. Product-level totals, component label panels, recipe estimates, and consumed nutrition are distinct. If a user omits a glaze, the API can exclude that component only when the panel and consumed amount support the calculation. It should not proportion a combined box total by weight and call the result exact.

Reconciliation is the operational feature

At pack time or receipt time, compare expected components with observations and produce typed outcomes:

  • fulfilled_exactly
  • substituted_approved
  • substituted_unapproved
  • missing
  • quantity_short
  • damaged
  • temperature_exception
  • condition_unknown

Do not infer “spoiled” from a late timestamp alone. Shipping duration, scan gaps, packaging, ambient conditions, and food-specific limits do not prove product condition. Preserve sensor readings and customer reports as evidence, then apply an explicit policy. Unknown is preferable to fabricated certainty.

Reconciliation should also calculate consequences, not just counts. A missing lime garnish may leave the meal cookable; a missing primary protein may not. A replacement sauce may preserve cookability while invalidating allergen or sodium constraints. A larger package may satisfy quantity but change the nutrition basis and leftovers. Useful output includes:

{
  "cookability": "blocked",
  "affectedRequirements": ["req:protein"],
  "constraintRecheck": ["allergens", "diet", "nutrition"],
  "remedyOptions": ["replace_component", "partial_refund"],
  "nutritionStatus": "stale_after_substitution"
}

That object gives customer support, the cooking UI, and an automated meal planner the same facts while allowing each to choose a different presentation.

Edge cases to decide before launch

  • Shared packets: one spice packet used by two meals needs allocation links, not duplicated inventory.
  • External items: refrigerated proteins packed outside a meal bag still need meal associations.
  • Multi-panel products: each food component may have its own serving basis and ingredient statement.
  • Partial consumption: “sauce served on the side” requires an observed amount before consumed nutrition can be precise.
  • Recipe swaps: replacing a side may alter steps and timing as well as ingredients.
  • Pack-size variance: an overweight produce item fulfills the requirement but should not automatically increase assumed consumption.
  • Claims without scans: customer reports are legitimate evidence with a different source and confidence than warehouse scans.
  • Retry and replacement: a replacement shipment should link to the failed component and claim rather than appearing as a duplicate order.

An API review checklist

Before exposing kits or multi-food packages, verify that the system can:

  • version recipes and sellable kit configurations independently;
  • assign component IDs that survive ordering changes within a revision;
  • distinguish included, customer-supplied, optional, and shared components;
  • map each supplied component to recipe requirements and instruction steps;
  • retain both required quantity and promised package quantity;
  • keep selectable swaps separate from fulfillment substitutions;
  • attach ingredients, allergens, and nutrition to the correct component and basis;
  • append actual packing and receipt evidence without mutating catalog truth;
  • recalculate cookability and constraints after missing or substituted items;
  • return unknown when condition or consumption cannot be established;
  • support component-level credits, refunds, replacements, and audit trails;
  • reproduce exactly what a customer was promised for any historical order.

A September 4 Supermarket News analysis argues that shopping agents will increasingly plan meals, consider household inventory, recommend quantities, and source across stores—and that accurate inventory and fulfillment data will help determine which retailers those agents choose. That future raises the cost of blurred states. An agent cannot repair a meal plan if the API cannot say whether an ingredient was required, promised, substituted, or received.

A components array is therefore more than a nested-data convenience. It is the bridge from a product record to a manifest. The durable design goes one step further: preserve recipe, box, and delivery as three linked truths, then reconcile them explicitly. That structure supports accurate nutrition, explainable substitutions, practical remedies, and meal plans that respond to what is actually available rather than what a catalog once promised.

Sources

Start Building

One consistent schema on every response. Get a free key and ship in minutes.