Skip to content

Products

PUT /products

Creates or updates products and modifier groups. Send only products that changed, and send them before pushing that day's transactions.

Authentication: API key (x-functions-key)

Request

Request body

Field Type Required Description
batch_id UUID Yes Idempotency key
products array of Product Yes 0–500 products. May be empty when you only update modifier groups.
modifier_groups array of ModifierGroup No Modifier groups that changed; upserted by group_id

Product object

Field Type Required Description
product_id string Yes Your product code
store_id string | null No Set for a store-specific product; null or omitted means all stores
sku string No Barcode or SKU
name localized text Yes Product name, at least one language
category_id string No Category code
category_name localized text No Category name
unit_price decimal string Yes Selling price. Tax-inclusive or not according to the store's prices_include_tax.
currency string Yes ISO 4217
tax_category enum No See tax categories
status enum Yes ACTIVE / INACTIVE
effective_from timestamp No When the price takes effect
version integer Yes Increase by 1 on every change
last_modified_at timestamp Yes Last change time
product_type enum Yes SINGLE (à la carte) / COMBO (set meal) / SIDE / DRINK / MODIFIER (add-on)
modifier_group_ids array of string No group_ids of the modifier groups available for this product
combo_components array of ComboComponent No COMBO only: items included in the combo

ComboComponent object

Field Type Required Description
product_id string Yes product_id of the included item
quantity decimal string Yes Quantity
is_substitutable boolean Yes Whether the customer can swap this item
substitute_group_id string Conditional Required when is_substitutable is true: the group_id listing the allowed substitutes

ModifierGroup object

Field Type Required Description
group_id string Yes Modifier group code
name localized text Yes Group name
min_select integer Yes Minimum selections (0 = optional)
max_select integer Yes Maximum selections (≥ min_select)
options array of ModifierOption Yes At least 1 option

ModifierOption object

Field Type Required Description
option_id string Yes Option code. If it equals a product_id (e.g. the drink upgrade DRK-BOBA), choosing it means choosing that product.
name localized text Yes Option name
price_delta decimal string Yes Extra charge (may be "0.00")
is_default boolean No Whether this is the default option. Default false.

Example

{
  "batch_id": "9c4b2a77-0d1e-4f3a-b5c6-7d8e9f0a1b2c",
  "products": [
    {
      "product_id": "COMBO-02",
      "store_id": null,
      "name": { "en-US": "Master Jimbo Combo" },
      "category_id": "COMBO",
      "unit_price": "14.49",
      "currency": "USD",
      "tax_category": "STANDARD",
      "status": "ACTIVE",
      "product_type": "COMBO",
      "modifier_group_ids": ["FLAVOR_JIMBO", "COMBO_DRINK"],
      "combo_components": [
        { "product_id": "SGL-JIMBO",    "quantity": "1", "is_substitutable": false },
        { "product_id": "SIDE-FRIES",   "quantity": "1", "is_substitutable": false },
        { "product_id": "DRK-FOUNTAIN", "quantity": "1", "is_substitutable": true, "substitute_group_id": "COMBO_DRINK" }
      ],
      "version": 1,
      "last_modified_at": "2026-10-14T10:00:00-07:00"
    },
    {
      "product_id": "SIDE-FRIES",
      "name": { "en-US": "Fries" },
      "unit_price": "4.49",
      "currency": "USD",
      "tax_category": "STANDARD",
      "status": "ACTIVE",
      "product_type": "SIDE",
      "modifier_group_ids": ["FRIES_EXTRA_FLAVOR"],
      "version": 1,
      "last_modified_at": "2026-10-14T10:00:00-07:00"
    }
  ],
  "modifier_groups": [
    {
      "group_id": "FRIES_EXTRA_FLAVOR",
      "name": { "en-US": "Add Extra Flavor" },
      "min_select": 0,
      "max_select": 2,
      "options": [
        { "option_id": "SEAWEED",       "name": { "en-US": "Seaweed" },       "price_delta": "0.75" },
        { "option_id": "CHEESE_POWDER", "name": { "en-US": "Cheese Powder" }, "price_delta": "0.75" }
      ]
    }
  ]
}

A combo drink group where upgrades are other products:

{
  "group_id": "COMBO_DRINK",
  "name": { "en-US": "Combo Drink" },
  "min_select": 1, "max_select": 1,
  "options": [
    { "option_id": "DRK-FOUNTAIN",         "name": { "en-US": "Fountain Drinks" },           "price_delta": "0.00", "is_default": true },
    { "option_id": "DRK-TW-LEMONADE",      "name": { "en-US": "Taiwan Signature Lemonade" }, "price_delta": "2.50" },
    { "option_id": "DRK-KUMQUAT-LEMONADE", "name": { "en-US": "Kumquat Lemonade" },          "price_delta": "2.50" },
    { "option_id": "DRK-BOBA",             "name": { "en-US": "Taiwan Boba Tea" },           "price_delta": "3.50" }
  ]
}

Response

202 Accepted — record_count is the number of products.

{ "batch_id": "9c4b2a77-0d1e-4f3a-b5c6-7d8e9f0a1b2c", "status": "ACCEPTED", "record_count": 2, "warnings": [] }

Errors

HTTP code When
400 INVALID_PAYLOAD Invalid type, missing field, invalid enum, wrong decimal places
400 BATCH_TOO_LARGE More products than your batch limit
403 STORE_NOT_ALLOWED A product's store_id is not registered for your account
413 PAYLOAD_TOO_LARGE Body larger than 5 MB

Notes

  • How combos and modifiers appear in transactions is described in Recording Rules.
  • If a transaction arrives before its product, it is still accepted and matched once the product arrives.