Variable Weight Items

Variable weight items are products whose final charge depends on an actual measured weight rather than a fixed unit price. Fresh meat, fruit and veg, deli items, and ready-prepared meals are common examples. The Picking API now exposes the data integrators need to support these items end-to-end: item metadata at order placement, weight amendment submission during picking, and tolerance validation to catch weighing errors before they reach the customer.

This guide covers how variable weight data flows through the Picking API, how your picking application should handle each item type, and how to submit weight amendments once a picker has weighed an item.


Item Types

Variable weight items fall into two categories. Your picking application needs to handle them differently.

Pre-packed

Items with a standard labelled weight, individually wrapped and barcoded. The customer orders a quantity of units. Each unit has an expected label weight, but the actual weight varies from pack to pack.

Examples: 300g sirloin steak, 500g cubed lamb, 80g pot of olives, whole chicken.

The picker scans the barcode on the pack, records the actual weight, and submits it as an amendment. Tolerance is checked per unit against the expected label weight.

To-be-packed

Items weighed to order in-store. The customer selects a total weight in fixed increments (e.g. minimum 500g, then 500g steps). The picker weighs the item at a scale and records the actual total weight.

Examples: loose nuts, couscous, sliced ham from the deli counter.

Tolerance is checked against the total ordered weight.


How Variable Weight Data Appears in Orders

When an order contains variable weight items, each item includes a variable_measurement object and an is_variable_weight flag in the order response.

{
  "id": "drn:order-item:abc-123",
  "name": "Sirloin Steak 300g",
  "quantity": 1,
  "is_variable_weight": true,
  "variable_measurement": {
    "original_amount": 300,
    "unit": "grams",
    "increment": 1,
    "price_per_increment": {
      "currency_code": "GBP",
      "fractional": 5
    },
    "sold_by": "count",
    "minimum_allowed_final_amount": 270,
    "maximum_allowed_final_amount": 330,
    "tolerance_percentage_lower": 10,
    "tolerance_percentage_upper": 10
  }
}

Field reference

FieldTypeDescription
is_variable_weightbooleantrue for any variable weight item.
variable_measurement.original_amountfloatThe expected weight for this item. For pre-packed items, this is the per-unit label weight. For to-be-packed items, this is the total ordered weight.
variable_measurement.unitstringUnit of measurement: "grams" or "kilograms".
variable_measurement.incrementfloatThe base measurement step used for pricing.
variable_measurement.price_per_incrementobjectPrice per increment in the order currency.
variable_measurement.sold_bystring"count" for pre-packed items, "measurement" for to-be-packed items.
variable_measurement.minimum_allowed_final_amountfloatThe lowest acceptable weight for this item.
variable_measurement.maximum_allowed_final_amountfloatThe highest acceptable weight for this item.
variable_measurement.tolerance_percentage_lowerintLower tolerance percentage used to compute the minimum.
variable_measurement.tolerance_percentage_upperintUpper tolerance percentage used to compute the maximum.

The tolerance bounds are provided so your picking application can validate weights locally before submitting, giving pickers immediate feedback if a weight is outside the acceptable range. The server enforces the same bounds on amendment submission.

Pre-packed vs to-be-packed in practice

Pre-packed items (sold_by: "count") arrive from the order system as individual line items, one per physical unit. If a customer orders two 500g steaks, the order contains two separate items, each with original_amount: 500 and quantity: 1. Your picker weighs each steak individually.

To-be-packed items (sold_by: "measurement") appear as a single line item. If a customer orders 500g of olives, the order contains one item with original_amount: 500 (or 0.5 if the unit is kilograms). Your picker weighs the total amount at the counter.


Submitting Weight Amendments

Once a picker has weighed a variable weight item, submit an amendment to record the actual weight. Use the same amendment endpoints you already use for quantity changes and substitutions.

V2 endpoint

PUT /v2/picking/orders/{order_id}

{
  "item_amendments": [
    {
      "amends": { "id": "drn:order-item:abc-123" },
      "final_amount": 285,
      "barcode": "0212345678901",
      "prep_method": "PREP_METHOD_SCAN"
    }
  ]
}

V1 endpoint

POST /v1/picking/orders/{order_id}/amendments

{
  "item_amendments": [
    {
      "amends": { "id": "drn:order-item:abc-123", "quantity": 1 },
      "final_amount": 285,
      "barcode": "0212345678901",
      "prep_method": "PREP_METHOD_SCAN"
    }
  ]
}

Amendment fields

FieldTypeRequiredDescription
final_amountfloatYesThe actual measured weight in the same unit as original_amount.
barcodestringNoThe scanned barcode value from the item's label. Recommended for pre-packed items where barcode scanning is part of the picking workflow.
prep_methodstringNoHow the item weight was captured during picking. Either PREP_METHOD_SCAN (weight read from barcode scan) or PREP_METHOD_MANUAL (weight entered manually by the picker).

On a successful amendment, the response contains the updated order with recalculated totals reflecting the actual weight.

What happens after a valid amendment

Deliveroo recalculates the item price based on the actual weight:

final_price = (final_amount / increment) * price_per_increment

If the actual weight is less than ordered, the customer is automatically refunded for the difference. If the actual weight is more than ordered, it will be charged using the pre-authorization model.


Tolerance Validation

Amendments are validated against the tolerance bounds for the item. If the submitted weight falls outside the allowed range, the amendment is rejected with a 400 response.

Both pre-packed and to-be-packed items are validated the same way: final_amount must fall within [minimum_allowed_final_amount, maximum_allowed_final_amount].

Example: weight within tolerance

A steak with original_amount: 300 and ±10% tolerance allows weights between 270g and 330g.

{
  "item_amendments": [
    {
      "amends": { "id": "drn:order-item:abc-123" },
      "final_amount": 285
    }
  ]
}

Response: 200 OK with updated order.

Example: weight outside tolerance

Same steak, but the picker records 250g:

{
  "item_amendments": [
    {
      "amends": { "id": "drn:order-item:abc-123" },
      "final_amount": 250
    }
  ]
}

Response: 400 Bad Request

{
  "error": {
    "code": "bad_request",
    "message": "item[drn:order-item:abc-123] final_amount 250.000 is outside the allowed range [270.000, 330.000]",
    "errors": [
      {
        "code": "final_amount_out_of_range",
        "item_id": "drn:order-item:abc-123",
        "message": "final_amount 250.000 is outside the allowed range [270.000, 330.000]"
      }
    ]
  }
}

A rejected amendment does not alter the order. The item remains amendable and the partner may resubmit with a corrected weight.

Other validation errors

Error codeCause
missing_final_amountfinal_amount was not included in the amendment for a variable weight item.
invalid_final_amountfinal_amount is negative.
final_amount_out_of_rangefinal_amount falls outside the tolerance bounds.

Item Removal

If a picker cannot find an item within the configured tolerance, or the item is unavailable entirely, submit an ITEM_REMOVAL amendment. This is the standard removal flow — send final_amount: 0 for the variable weight item.

For pre-packed items where the customer ordered multiple units (multiple line items), remove each unavailable item individually using its own item ID.

Substitutions are not permitted for variable weight items at MVP. The API returns only ITEM_REMOVAL in allowed_actions_if_items_are_unavailable for variable weight items.


Recommended Integration Flow

  1. Receive order — check each item for is_variable_weight: true.
  2. Display to picker — for pre-packed items, show the expected label weight and prompt for a barcode scan. For to-be-packed items, show the ordered weight and prompt for scale entry. Display the allowed range from minimum_allowed_final_amount and maximum_allowed_final_amount.
  3. Validate locally — before submitting, check the entered weight falls within the tolerance bounds. This avoids unnecessary round-trips for out-of-range weights.
  4. Submit amendment — call the amendment endpoint with final_amount (and optionally barcode for pre-packed items).
  5. Handle errors — if the amendment is rejected due to tolerance, prompt the picker to re-weigh. If the item is genuinely outside tolerance, submit an ITEM_REMOVAL.
  6. Continue with remaining items — variable weight amendments can be interleaved with regular amendments for non-VW items.
  7. Accept order — once all items are picked and all amendments submitted, call the accept endpoint as normal.

Completion Webhook

The order completion webhook (order.status_update with status "accepted") includes variable weight data for each item. The variable_measurement object on completed items includes final_amount reflecting the actual picked weight, alongside the original order metadata. The barcode field on the item reflects the value submitted during the amendment.


Common Questions

Do I need to change my existing amendment integration?

No. Variable weight amendments use the same endpoints and the same request structure. The only addition is the final_amount field. Existing non-VW amendments continue to work unchanged.

What if my picker scans a barcode — do I need to send it?

The barcode field is optional. We recommend sending it for pre-packed items where the picker scans the pack, as it is stored against the order item for downstream reconciliation. The value is treated as an opaque string — Deliveroo does not validate the barcode format.

Can I submit amendments for multiple variable weight items in one request?

Yes. Include multiple entries in the item_amendments array, each with its own final_amount. Each item is validated independently.

What if the weight is exactly zero?

Sending final_amount: 0 is treated as a removal. The item will be archived and the customer refunded.

What happens if I submit a weight and then need to correct it?

Once an item has been amended, it cannot be amended again. The picker should weigh carefully before submitting. If a mistake is made, contact Deliveroo support for manual correction.

Why are there two separate items when a customer orders two steaks?

Pre-packed items are individual physical units. Each pack has its own weight and barcode, so each appears as a separate line item in the order. The picker weighs and amends each one independently.

Can I substitute a variable weight item?

Currently, substitutions are blocked for variable weight items. If an item is unavailable, the only option is removal.

What units does final_amount use?

The same unit as original_amount, which is specified in variable_measurement.unit. If the unit is "grams", send final_amount in grams. If "kilograms", send in kilograms.

Are tolerance percentages always 10%?

No. Tolerance is configured per site. The actual bounds are provided in the order response as minimum_allowed_final_amount and maximum_allowed_final_amount. Always validate against these values rather than assuming a fixed percentage.