Do we have these products?
inventory.product.have
GET/api/v1/households/{household_id}/queries/inventory.product.have
- Query
- Rigel runs it
For each product: the items recorded with amounts, places and when each was last seen, and whether it's a staple and whether the household tracks it. It answers with what's recorded and how fresh that is; judging whether it's still true is the caller's job. Untracked products have no items by design, so their absence means nothing. IDs that aren't products are listed in unknown_product_ids.
Parameters#
| Field | Description |
|---|---|
household_idpathstringrequired | The household's ID. |
product_idsqueryarray of stringsrequired | The products to look up, 1–200. |
Response#
200 The answer.
| Field | Description |
|---|---|
productsarray of objectsrequired | |
products[].product_idstringrequired | A product ID, such as prd_01JC0000000000000000000000. |
products[].namestringrequired | No description. |
products[].is_staplebooleanrequired | No description. |
products[].is_trackedbooleanrequired | No description. |
products[].itemsarray of objectsrequired | What we have, soonest to expire first. Empty when none is recorded. |
products[].items[].item_idstringrequired | A inventory item ID, such as inv_01JC0000000000000000000000. |
products[].items[].amountstringrequired | The amount in words: "2 cans", "about half", "some". |
products[].items[].quantitynumber or nullrequired | The number we have, in quantity_unit, or null when we don't know one. |
products[].items[].quantity_unitone of: mg, g, kg, oz, lb, ml, l, tsp, tbsp, fl_oz, cup, pint, quart, gallon, pinch, dash, clove, slice, stick, sprig, head, bunch, stalk, can, jar, bottle, box, bag, package, carton, roll, null or nullrequired | A unit. Mass: mg, g, kg, oz, lb. Volume (US sizes): ml, l, tsp, tbsp, fl_oz, cup, pint, quart, gallon. Items, for a count of something other than the thing itself (2 cloves of garlic, 1 can of beans): pinch, dash, clove, slice, stick, sprig, head, bunch, stalk, can, jar, bottle, box, bag, package, carton, roll. Leave it out or null for a plain count of the things themselves (3 eggs). |
products[].items[].levelone of: full, most, half, low, null or nullrequired | A rough amount when there's no number: full, most (mostly full), half (about half) or low. Leave both quantity and level out for "we have some". |
products[].items[].location_idstringrequired | A storage location ID, such as loc_01JC0000000000000000000000. |
products[].items[].locationstringrequired | Where it is, from the top: "Kitchen pantry › Middle shelf". |
products[].items[].expires_onstring or nullrequired | When to use it by, YYYY-MM-DD, or null if it doesn't go bad. |
products[].items[].expires_sourceone of: label, person, estimated, null or nullrequired | Where expires_on came from: label (read off the package), person (someone told us) or estimated (Rigel worked it out from what it is, where it's kept and when it was bought, made or opened). |
products[].items[].confirmed_atstring (date-time)required | When this item's amount was last known to be true. |
products[].items[].seen_agostringrequired | How long ago that was, in words: "3 days ago". |
unknown_product_idsarray of stringsrequired | Requested IDs with no product. |
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.
Do we have these?
Repeat product_ids for each product. Each answer says how much, where and how long ago it was last seen.
curl 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/inventory.product.have?product_ids=prd_01M6V9CSAG72MC7ERJ4GCZ0X7A&product_ids=prd_01M6V9CSAMSN9ZJ52PTTKT8G6M' \
-H "Cookie: rigel_session=$RIGEL_SESSION"const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/inventory.product.have?product_ids=prd_01M6V9CSAG72MC7ERJ4GCZ0X7A&product_ids=prd_01M6V9CSAMSN9ZJ52PTTKT8G6M", {
headers: {
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
});
const data = await response.json();GET /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/inventory.product.have?product_ids=prd_01M6V9CSAG72MC7ERJ4GCZ0X7A&product_ids=prd_01M6V9CSAMSN9ZJ52PTTKT8G6M HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CSBDZMW1ZRHTRG80QEYQ
{
"products": [
{
"product_id": "prd_01M6V9CSAG72MC7ERJ4GCZ0X7A",
"name": "Flour",
"is_staple": true,
"is_tracked": true,
"items": [
{
"item_id": "inv_01M6V9CSAJYYMNC0TXJX8NRN8T",
"amount": "1 bag",
"quantity": 1,
"quantity_unit": "bag",
"level": null,
"location_id": "loc_01M6V9CSA910340EZNX67RFMV0",
"location": "Kitchen pantry › Middle shelf",
"expires_on": null,
"expires_source": null,
"confirmed_at": "2026-11-07T15:17:52.083Z",
"seen_ago": "just now"
}
]
},
{
"product_id": "prd_01M6V9CSAMSN9ZJ52PTTKT8G6M",
"name": "Black beans",
"is_staple": false,
"is_tracked": true,
"items": [
{
"item_id": "inv_01M6V9CSAPM8JH7W1W1YEBHPRS",
"amount": "3 cans",
"quantity": 3,
"quantity_unit": "can",
"level": null,
"location_id": "loc_01M6V9CSA910340EZNX67RFMV0",
"location": "Kitchen pantry › Middle shelf",
"expires_on": null,
"expires_source": null,
"confirmed_at": "2026-11-07T15:17:52.086Z",
"seen_ago": "just now"
}
]
}
],
"unknown_product_ids": []
}Ask about a product that isn't there
Unknown IDs come back in unknown_product_ids, not as an error.
curl 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/inventory.product.have?product_ids=prd_01M6V9CSAG72MC7ERJ4GCZ0X7A&product_ids=prd_01JC0000000000000000000000' \
-H "Cookie: rigel_session=$RIGEL_SESSION"const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/inventory.product.have?product_ids=prd_01M6V9CSAG72MC7ERJ4GCZ0X7A&product_ids=prd_01JC0000000000000000000000", {
headers: {
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
});
const data = await response.json();GET /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/queries/inventory.product.have?product_ids=prd_01M6V9CSAG72MC7ERJ4GCZ0X7A&product_ids=prd_01JC0000000000000000000000 HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CSBGQGRZ4D6R6TZ97YCH
{
"products": [
{
"product_id": "prd_01M6V9CSAG72MC7ERJ4GCZ0X7A",
"name": "Flour",
"is_staple": true,
"is_tracked": true,
"items": [
{
"item_id": "inv_01M6V9CSAJYYMNC0TXJX8NRN8T",
"amount": "1 bag",
"quantity": 1,
"quantity_unit": "bag",
"level": null,
"location_id": "loc_01M6V9CSA910340EZNX67RFMV0",
"location": "Kitchen pantry › Middle shelf",
"expires_on": null,
"expires_source": null,
"confirmed_at": "2026-11-07T15:17:52.083Z",
"seen_ago": "just now"
}
]
}
],
"unknown_product_ids": [
"prd_01JC0000000000000000000000"
]
}For Rigel#
Rigel's tool for this query is inventory_product_have. Rigel runs this on its own, then says what it did. The agent guide has the rest.