What a week's meals need from the store
meals.week.groceries
GET/api/v1/households/{household_id}/queries/meals.week.groceries
- Query
- Rigel runs it
One item per product across the week's meals, with the amount notes, which meals need it, whether it's a staple, and what inventory has recorded of it. A dish's notes are the ones written on it; a dish with a recipe buys the recipe's ingredients, scaled to the number of people in the meal (people over the recipe's servings), with the scaled amount as the note, and leaves out optional ingredients. A recipe ingredient with no product has product_id null and is grouped by its lowercased name. Dishes eaten away from home are skipped. Dishes with no ingredients listed are returned separately in dishes_without_ingredients, because their groceries aren't known yet (set them with meals.dish.set_ingredients). on_list is the product's item on the shopping list, if it has one still to get, with the meals of this week it's already for; add the rest with shopping.item.add_many, once per meal.
Parameters#
| Field | Description |
|---|---|
household_idpathstringrequired | The household's ID. |
week_startquerystring (date)required | The first day of the plan week, YYYY-MM-DD. The week is the 7 days starting on it; screens use the household's week_starts_on day. |
Response#
200 The answer.
| Field | Description |
|---|---|
itemsarray of objectsrequired | The products, sorted by name. |
items[].product_idstring or nullrequired | The product to buy, from the shared product list; null for a recipe ingredient that names no product, which is grouped by its lowercased name. |
items[].namestringrequired | The product's name, or the recipe ingredient's name when product_id is null. |
items[].is_staplebooleanrequired | Something the household normally has, such as salt or oil: worth checking before buying. |
items[].amount_notesarray of stringsrequired | The amounts, such as "1 pack" written on a dish, or "1½ cups" from a recipe scaled to the meal's people (one per meal, not added up). |
items[].needed_forarray of objectsrequired | The meals that need it. |
items[].needed_for[].meal_idstringrequired | A meal ID, such as mel_01JC0000000000000000000000. |
items[].needed_for[].labelstringrequired | The meal, such as "Tue dinner". |
items[].in_houseobject or nullrequired | What inventory has recorded of it, or null when it records none. Judge how fresh it is. |
items[].in_house.locationsarray of stringsrequired | Where inventory says it is, such as "Pantry". |
items[].in_house.confirmed_atstring (date-time)required | When an item of it was last known to be there. |
items[].on_listobject or nullrequired | The product's item on the shopping list that's still to get, or null when it isn't on the list. A recipe ingredient with no product matches a product of the same name. |
items[].on_list.shopping_item_idstringrequired | A shopping list item ID, such as shi_01JC0000000000000000000000. |
items[].on_list.notestring or nullrequired | The list item's note, as written. |
items[].on_list.meal_idsarray of stringsrequired | Which of needed_for the list item is already for. Adding for these again changes nothing. |
dishes_without_ingredientsarray of objectsrequired | Dishes eaten at home that have no ingredients listed yet. |
dishes_without_ingredients[].dish_idstringrequired | A dish ID, such as dsh_01JC0000000000000000000000. |
dishes_without_ingredients[].namestringrequired | The dish's name. |
dishes_without_ingredients[].needed_forarray of objectsrequired | The meals with this dish. |
dishes_without_ingredients[].needed_for[].meal_idstringrequired | A meal ID, such as mel_01JC0000000000000000000000. |
dishes_without_ingredients[].needed_for[].labelstringrequired | The meal, such as "Tue dinner". |
Errors#
Every error has the same envelope: error.code, error.message, error.details, error.recovery and error.request_id.
| Status | Code | When |
|---|---|---|
400 | validation_failed | A field is missing, misspelled or out of range. details.fields lists each problem. |
401 | unauthenticated | The request has no valid session. |
404 | not_found | The household doesn't exist, or you aren't a member of it. |
Examples#
These are real. Each was recorded from a sample household, the Okafors, running through the whole API when this site was built.
What the week needs from the store
Each item says which meals need it and whether the household has it.
curl 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/meals.week.groceries?week_start=2026-11-09' \
-H "Cookie: rigel_session=$RIGEL_SESSION"const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/meals.week.groceries?week_start=2026-11-09", {
headers: {
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
});
const data = await response.json();GET /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/meals.week.groceries?week_start=2026-11-09 HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CSGAR0HN1D1STM2MEMSM
{
"items": [
{
"product_id": null,
"name": "baking powder",
"is_staple": false,
"amount_notes": [
"2 tsp"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXTVMCRYCPZFGJP37A",
"label": "Sat breakfast"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": "prd_01M6V9CSAMSN9ZJ52PTTKT8G6M",
"name": "Black beans",
"is_staple": false,
"amount_notes": [
"1 can"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXHKGZVJ1H2H384CNQ",
"label": "Tue dinner"
}
],
"in_house": {
"locations": [
"Middle shelf"
],
"confirmed_at": "2026-11-07T15:17:52.148Z"
},
"on_list": null
},
{
"product_id": null,
"name": "butter",
"is_staple": false,
"amount_notes": [
"3 tbsp"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXTVMCRYCPZFGJP37A",
"label": "Sat breakfast"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": "prd_01M6V9CSB2GBRX2QG46DDBK4TW",
"name": "Chicken thighs",
"is_staple": false,
"amount_notes": [
"about 2 lb"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXHKGZVJ1H2H384CNQ",
"label": "Tue dinner"
}
],
"in_house": {
"locations": [
"Kitchen fridge"
],
"confirmed_at": "2026-11-07T15:17:52.099Z"
},
"on_list": null
},
{
"product_id": null,
"name": "crushed tomatoes",
"is_staple": false,
"amount_notes": [
"1 can"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
"label": "Mon dinner"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": null,
"name": "eggs",
"is_staple": false,
"amount_notes": [
"2"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXTVMCRYCPZFGJP37A",
"label": "Sat breakfast"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": "prd_01M6V9CSAG72MC7ERJ4GCZ0X7A",
"name": "Flour",
"is_staple": true,
"amount_notes": [
"2 cups"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXTVMCRYCPZFGJP37A",
"label": "Sat breakfast"
}
],
"in_house": {
"locations": [
"Middle shelf"
],
"confirmed_at": "2026-11-07T15:17:52.148Z"
},
"on_list": null
},
{
"product_id": null,
"name": "garlic",
"is_staple": false,
"amount_notes": [
"3–4 cloves"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
"label": "Mon dinner"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": "prd_01M6V9CSAWSAMCWTBQ2M7F80H9",
"name": "Milk",
"is_staple": true,
"amount_notes": [
"1½ cups"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXTVMCRYCPZFGJP37A",
"label": "Sat breakfast"
}
],
"in_house": {
"locations": [
"Kitchen fridge"
],
"confirmed_at": "2026-11-07T15:17:52.163Z"
},
"on_list": null
},
{
"product_id": "prd_01M6V9CSAT6M58YWZ1H4DFY9K2",
"name": "Olive oil",
"is_staple": false,
"amount_notes": [
"2 tbsp"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
"label": "Mon dinner"
}
],
"in_house": {
"locations": [
"Middle shelf"
],
"confirmed_at": "2026-11-07T15:17:52.148Z"
},
"on_list": null
},
{
"product_id": "prd_01M6V9CSAQDSZHDQNXHXRCDA8Z",
"name": "Orzo",
"is_staple": false,
"amount_notes": [
"1 cup"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
"label": "Mon dinner"
}
],
"in_house": {
"locations": [
"Middle shelf"
],
"confirmed_at": "2026-11-07T15:17:52.148Z"
},
"on_list": null
},
{
"product_id": null,
"name": "salt",
"is_staple": false,
"amount_notes": [
"1 pinch"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXTVMCRYCPZFGJP37A",
"label": "Sat breakfast"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": "prd_01M6V9CSFAPVK126M4A4P3X1QS",
"name": "Tortillas",
"is_staple": false,
"amount_notes": [
"8 small"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXHKGZVJ1H2H384CNQ",
"label": "Tue dinner"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": null,
"name": "vegetable broth",
"is_staple": false,
"amount_notes": [
"3 cups"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
"label": "Mon dinner"
}
],
"in_house": null,
"on_list": null
},
{
"product_id": null,
"name": "white beans",
"is_staple": false,
"amount_notes": [
"1 can"
],
"needed_for": [
{
"meal_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
"label": "Mon dinner"
}
],
"in_house": null,
"on_list": null
}
],
"dishes_without_ingredients": [
{
"dish_id": "dsh_01M6V9CSFXV5STR8CP8W0Q1QSC",
"name": "Pizza night",
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXM0D756CP5KY4HP4Q",
"label": "Fri dinner"
}
]
},
{
"dish_id": "dsh_01M6V9CSFX14RRNZFQNPVECMDB",
"name": "Sheet pan sausage and potatoes",
"needed_for": [
{
"meal_id": "mel_01M6V9CSFX452XJRFQ0A5WTYPH",
"label": "Thu dinner"
}
]
},
{
"dish_id": "dsh_01M6V9CSFX72P8209NS1P4AX7B",
"name": "Turkey chili",
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXE8ZNK29NR2EPTDDZ",
"label": "Sun dinner"
}
]
},
{
"dish_id": "dsh_01M6V9CSFXQ42NCQ1HWBY8559H",
"name": "Veggie quesadillas",
"needed_for": [
{
"meal_id": "mel_01M6V9CSFXGQ25SM1HSAWPM40J",
"label": "Wed dinner"
}
]
}
]
}For Rigel#
Rigel's tool for this query is meals_week_groceries. Rigel runs this on its own, then says what it did. The agent guide has the rest.