Skip to content

Deliveries and meals

HelloFresh identifies a box by an ISO week such as 2026-W40. The week you can still edit is usually later than the box that is already locked for delivery.

get_meals_for_week_offset() starts at the latest locked delivery and walks by whole ISO weeks.

Offset Week
0 Newest scheduled week whose cutoff has already passed. This is the box arriving now.
1 The following week, still open for selection when its cutoff is in the future.
-1 The delivery before the locked box.
current = await client.get_meals_for_week_offset(0)
following = await client.get_meals_for_week_offset(1)
previous = await client.get_meals_for_week_offset(-1)

for meal in current:
    if meal.recipe:
        print(f"{meal.quantity} x {meal.recipe.name}")

The method loads the delivery schedule from eight weeks before the current ISO week through six weeks after it, picks the anchor week, then loads that week's menu. Only meals with selection.quantity > 0 are returned. Meal.selected is that check, and Meal.quantity is the count.

Paused, cancelled, and donated weeks are skipped while another delivery remains. A schedule with no usable week raises HelloFreshError.

How the anchor is chosen

  1. Keep weeks whose cutoff is already in the past, and take the newest of those.
  2. If no cutoff is present, keep deliveries dated no later than seven days from now, and take the newest of those.
  3. Otherwise take the newest week id in the schedule.
from datetime import datetime, timezone
from pyhellofresh.weeks import select_latest_delivery_week, shift_iso_week

latest = select_latest_delivery_week(deliveries.weeks, datetime.now(timezone.utc))
target = shift_iso_week(latest, 1)

Delivery schedule

schedule = await client.get_past_deliveries("2026-W36", "2026-W42")
print(schedule.next_week)
for week in schedule.weeks:
    print(week.week, week.status, week.cutoff_date, week.delivery_date)

range_start and range_end are optional ISO week ids sent as rangeStart and rangeEnd. Omit them and the gateway uses its default window, which is often only the upcoming editable week.

Each PastDeliveryItem exposes:

Field Source
week week, hfWeek, or an id that already looks like 2026-W40
cutoff_date cutoffDate or cutoffDateTime
delivery_date deliveryDate or deliveryDateTime
status status, or state when status is empty
menu_id menuId
meals, addons Raw objects from the payload, when the endpoint includes them

next_week is the payload's nextWeek value. On the past-deliveries pagination API that field is a cursor toward older weeks. It is not, by itself, the next menu you can edit. Use get_meals_for_week_offset(1) for that box.

The schedule parser accepts either a weeks list or an items list.

Week helpers

pyhellofresh.weeks.current_iso_week

current_iso_week(moment: datetime) -> str

Return the ISO week id that contains moment.

Source code in src/pyhellofresh/weeks.py
def current_iso_week(moment: datetime) -> str:
    """Return the ISO week id that contains ``moment``."""
    iso = moment.date().isocalendar()
    return f"{iso.year}-W{iso.week:02d}"

pyhellofresh.weeks.shift_iso_week

shift_iso_week(week: str, offset: int) -> str

Move an ISO week id by offset weeks.

Parameters:

Name Type Description Default
week str

Week id such as 2026-W40.

required
offset int

Number of weeks to add. Negative values move backward.

required

Returns:

Type Description
str

The shifted week id.

Raises:

Type Description
HelloFreshError

If week is not an ISO week id.

Source code in src/pyhellofresh/weeks.py
def shift_iso_week(week: str, offset: int) -> str:
    """Move an ISO week id by ``offset`` weeks.

    Args:
        week: Week id such as ``2026-W40``.
        offset: Number of weeks to add. Negative values move backward.

    Returns:
        The shifted week id.

    Raises:
        HelloFreshError: If ``week`` is not an ISO week id.
    """
    monday = _week_monday(week)
    shifted = monday + timedelta(weeks=offset)
    iso = shifted.isocalendar()
    return f"{iso.year}-W{iso.week:02d}"

pyhellofresh.weeks.select_latest_delivery_week

select_latest_delivery_week(
    weeks: list[PastDeliveryItem], now: datetime
) -> str

Pick the newest delivery week whose cutoff has already passed.

That week is the locked box: it is arriving now or has just been delivered. Later weeks in the schedule are still open for selection. Paused, cancelled, and donated weeks are ignored while another delivery remains.

Parameters:

Name Type Description Default
weeks list[PastDeliveryItem]

Delivery weeks from the customer schedule.

required
now datetime

Instant used to decide which cutoffs have passed.

required

Returns:

Type Description
str

ISO week id of the latest locked delivery.

Raises:

Type Description
HelloFreshError

If the schedule has no usable delivery week.

Source code in src/pyhellofresh/weeks.py
def select_latest_delivery_week(
    weeks: list[PastDeliveryItem],
    now: datetime,
) -> str:
    """Pick the newest delivery week whose cutoff has already passed.

    That week is the locked box: it is arriving now or has just been delivered.
    Later weeks in the schedule are still open for selection. Paused, cancelled,
    and donated weeks are ignored while another delivery remains.

    Args:
        weeks: Delivery weeks from the customer schedule.
        now: Instant used to decide which cutoffs have passed.

    Returns:
        ISO week id of the latest locked delivery.

    Raises:
        HelloFreshError: If the schedule has no usable delivery week.
    """
    if now.tzinfo is None:
        now = now.replace(tzinfo=UTC)

    candidates = [item for item in weeks if _is_iso_week(item.week)]
    if not candidates:
        raise HelloFreshError("No delivery weeks were returned.")

    active = [
        item
        for item in candidates
        if (item.status or "").upper() not in _SKIPPED_STATUSES
    ]
    pool = active or candidates

    locked = [
        item
        for item in pool
        if (cutoff := _parse_api_datetime(item.cutoff_date)) is not None
        and cutoff <= now
    ]
    if locked:
        return max(locked, key=_week_sort_key).week

    dated: list[tuple[datetime, PastDeliveryItem]] = []
    for item in pool:
        delivery = _parse_api_datetime(item.delivery_date)
        if delivery is not None:
            dated.append((delivery, item))
    if dated:
        window_end = now + timedelta(days=7)
        in_window = [(when, item) for when, item in dated if when <= window_end]
        chosen = in_window or dated
        return max(chosen, key=lambda pair: _week_sort_key(pair[1]))[1].week

    return max(pool, key=_week_sort_key).week