Batch Context

Purpose

This feature lets partners declare, at the moment they begin picking, whether the order is being picked alongside other orders in a batch — and if so, which batch and how it was composed.

Batch context is captured once per order at start-picking, persisted at the order level, surfaced on subsequent prep-state reads. It does not affect order acceptance, picking flow, or amendments.

Core Schema and Enums

BatchContext (object)

FieldTypeRequiredDescription
is_batchedboolyestrue if this order is being picked as part of a batch
batch_idstringwhen is_batched=truePartner-supplied identifier shared by all orders in the same batch
batch_sizeuint32when is_batched=trueNumber of orders in the batch (must be ≥ 2)
batch_scopeenumwhen is_batched=trueSee BatchScope below

BatchScope (enum)

  • SINGLE_AGGREGATOR — All orders in the batch originate from a single aggregator (e.g. all Deliveroo)
  • CROSS_AGGREGATOR — Orders in the batch span multiple aggregators

Key Architectural Principles

Captured once, at start-picking only:
Batch context is recorded at the moment picking begins and is not updated later in the order's lifecycle.

Order-level, not item-level:
Unlike prep-state and amendments, batch context attaches to the order, not to individual items. It appears alongside (not inside) the prep-state items on read responses.

Independent of amendments and prep-state:
Batch context does not interact with amendments, archival, or item-level updates. Amending an order does not clear, replace, or invalidate the recorded batch context.

API Endpoint

PUT /v1/picking/orders/{order_id}/start_picking

Request body:

{
  "batch_context": {
    "is_batched": true,
    "batch_id": "wave-123",
    "batch_size": 3,
    "batch_scope": "CROSS_AGGREGATOR"
  }
}
{
  "batch_context": { "is_batched": false }
}

Validation rules:

  • When is_batched = true:
    • batch_id is required and must be non-empty.
    • batch_size is required and must be ≥ 2. A missing/zero batch_size returns batch_size is required; values of 1 return batch_size must be >= 2.
    • batch_scope is required and must be one of SINGLE_AGGREGATOR or CROSS_AGGREGATOR.
  • When is_batched = false: batch_id, batch_size, and batch_scope must all be unset. Sending any of them alongside is_batched: false is rejected.
  • Malformed JSON is rejected with 400 BAD_REQUEST.

Successful response:

{ "message": "Preparation stage updated successfully" }

Recorded batch context is observable via the prep-state read endpoints (below).

Read-Back via Prep-State

Once batch context has been recorded for an order, it is included on prep-state reads:

GET /picking/v1/orders/{order_id}/prep-state

{
  "location_id": "...",
  "order_id": "...",
  "items": [ ... ],
  "batch_context": {
    "is_batched": true,
    "batch_id": "wave-123",
    "batch_size": 3,
    "batch_scope": "CROSS_AGGREGATOR"
  }
}

GET /picking/v1/orders/{order_id}/prep-state/items/{item_id}

The single-item response includes the same batch_context field at the top level.

Rules:

  • For non-batched orders, the response contains { "is_batched": false } with the optional fields absent.
  • batch_context is order-level metadata; it is identical across every item-level response for the same order.

Error Handling

Non-Retryable (4xx):

  • 400 BAD_REQUEST — Malformed JSON, or batch_context validation failure (missing batch_id, invalid batch_size, unrecognised batch_scope, or fields set when is_batched: false).
  • 401 UNAUTHORIZED — As per the existing start-picking contract.
  • 404 NOT_FOUND — Order does not exist.
  • 429 TOO_MANY_REQUESTS — The 1-request-per-order-per-30-seconds rate limit on start-picking applies unchanged.

Retryable (5xx):

  • 500 INTERNAL (failed to store batch context) — The order transition itself may not have completed; partners should retry the entire start-picking call. Retries with the same payload are safe.

Integration Best Practices

  1. Send batch context exactly once per order, in the start_picking request.
  2. Use a stable batch_id shared by every order in the same batch. The ID is partner-supplied and opaque to Deliveroo; choose a format that lets you correlate it back to your own dispatch records.
  3. Don't synthesise batches for single orders: if a picker is handling one order, send is_batched: false rather than a batch of size 1. batch_size = 1 is rejected.
  4. Do not depend on echo back in the start-picking response. If you need to confirm the recorded value, fetch the prep-state GET endpoint.