Put several things on the shopping list at once
shopping.item.add_many
POST/api/v1/households/{household_id}/commands/shopping.item.add_many
- Command
- Rigel runs it
- Applies offline
Adds up to 200 items, each as shopping.item.add takes it, in order, recorded as one change. Later items merge into earlier ones from the same batch, so the same product twice becomes one item. If any item is refused, nothing is added; the error names which item (counting from 1) and carries its position, counting from 0, as details.index. Returns one result per item, in order.
Parameters#
| Field | Description |
|---|---|
household_idpathstringrequired | The household's ID. |
Idempotency-Keyheaderstringoptional | The command's ID. Reuse it when retrying the same command. |
Request body#
JSON, as application/json.
| Field | Description |
|---|---|
itemsarray of objectsrequired | What to add, each as |
items[].product_idstringoptional | The product, when you know its ID. Give this or product_name. |
items[].product_namestringoptional | The product's name, when you don't have its ID: an existing product with this name (ignoring case) is used, or a new one is made. Search with |
items[].quantitynumber or nulloptional | How many, when said. Leave out when no amount was given. |
items[].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 nulloptional | 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). |
items[].notestring or nulloptional | A note for whoever shops: "plain", "the big bag". Name a meal or recipe with meal_id or recipe_id, not here, as written, 1–500 characters. |
items[].for_person_idstring or nulloptional | Who it's for, when someone said it's for a person in the family. |
items[].meal_idstring or nulloptional | The planned meal it's for, from the meal plan, so the list shows the meal and follows it if it moves. For something several meals need, add it once per meal. |
items[].recipe_idstring or nulloptional | The recipe it's for, when it comes from a recipe's ingredients, so the list can say so. For something several recipes need, add it once per recipe. |
Response#
200 The command was applied.
| Field | Description |
|---|---|
resultobjectrequired | What the command returned, such as the IDs it created. |
result.itemsarray of objectsrequired | One result per input item, in the same order. |
result.items[].item_idstringrequired | The list item: the new one, or the one already on the list that this was added to. |
result.items[].product_idstringrequired | The product it's for. |
result.items[].mergedbooleanrequired | True when the product was already on the list and this was added to that item. |
versionintegerrequired | The household version after the command. |
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 | product_not_found | A refused item rejects the whole batch. |
404 | person_not_found | An unknown person in a later item rejects the whole batch. |
404 | not_found | The household doesn't exist, or you aren't a member of it. |
409 | idempotency_key_reused | The Idempotency-Key was already used for a different command. |
Examples#
These are real. Each scenario is one of the command's test cases, run on a household when this site was built, and the response is what the API returned.
Several items are added in order
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"items": [
{
"product_id": "prd_01JC000000000000000000000A",
"quantity": 1,
"unit": "gallon"
},
{
"product_name": "Rice"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
items: [
{
product_id: "prd_01JC000000000000000000000A",
quantity: 1,
unit: "gallon",
},
{
product_name: "Rice",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"items": [
{
"product_id": "prd_01JC000000000000000000000A",
"quantity": 1,
"unit": "gallon"
},
{
"product_name": "Rice"
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R09J8VQASV32QPEH65
{
"result": {
"items": [
{
"item_id": "shi_01JC4N0000MBGE5RJ6Q7V6V6T8",
"product_id": "prd_01JC000000000000000000000A",
"merged": false
},
{
"item_id": "shi_01JC4N0000JVP6PWJ6S8P7WZ6B",
"product_id": "prd_01JC4N0000VGW1STJ6TGXRB7FY",
"merged": false
}
]
},
"version": 1
}A later item merges into an earlier one from the same batch
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"items": [
{
"product_id": "prd_01JC000000000000000000000B",
"quantity": 6
},
{
"product_name": "eggs",
"quantity": 6,
"note": "for baking"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
items: [
{
product_id: "prd_01JC000000000000000000000B",
quantity: 6,
},
{
product_name: "eggs",
quantity: 6,
note: "for baking",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"items": [
{
"product_id": "prd_01JC000000000000000000000B",
"quantity": 6
},
{
"product_name": "eggs",
"quantity": 6,
"note": "for baking"
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R049HPV8DYQJYD2Z7J
{
"result": {
"items": [
{
"item_id": "shi_01JC4N0000MBGE5RJ6Q7V6V6T8",
"product_id": "prd_01JC000000000000000000000B",
"merged": false
},
{
"item_id": "shi_01JC4N0000MBGE5RJ6Q7V6V6T8",
"product_id": "prd_01JC000000000000000000000B",
"merged": true
}
]
},
"version": 1
}A later item merges into an item already on the list
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"items": [
{
"product_id": "prd_01JC000000000000000000000C"
},
{
"product_id": "prd_01JC000000000000000000000A",
"quantity": 1,
"unit": "gallon"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
items: [
{
product_id: "prd_01JC000000000000000000000C",
},
{
product_id: "prd_01JC000000000000000000000A",
quantity: 1,
unit: "gallon",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"items": [
{
"product_id": "prd_01JC000000000000000000000C"
},
{
"product_id": "prd_01JC000000000000000000000A",
"quantity": 1,
"unit": "gallon"
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R00TNHVSH2QV1X6GXB
{
"result": {
"items": [
{
"item_id": "shi_01JC4N0000MBGE5RJ6Q7V6V6T8",
"product_id": "prd_01JC000000000000000000000C",
"merged": false
},
{
"item_id": "shi_01JC0000000000000000000001",
"product_id": "prd_01JC000000000000000000000A",
"merged": true
}
]
},
"version": 1
}A refused item rejects the whole batch
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"items": [
{
"product_id": "prd_01JC000000000000000000000A"
},
{
"product_id": "prd_01JC000000000000000000000Z"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
items: [
{
product_id: "prd_01JC000000000000000000000A",
},
{
product_id: "prd_01JC000000000000000000000Z",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"items": [
{
"product_id": "prd_01JC000000000000000000000A"
},
{
"product_id": "prd_01JC000000000000000000000Z"
}
]
}HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R07AEYKZ1VNMEKQJCV
{
"error": {
"code": "product_not_found",
"message": "Item 2: That product isn't there any more. No changes were applied.",
"details": {
"product_id": "prd_01JC000000000000000000000Z",
"index": 1
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R07AEYKZ1VNMEKQJCV"
}
}An unknown person in a later item rejects the whole batch
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"items": [
{
"product_id": "prd_01JC000000000000000000000A"
},
{
"product_id": "prd_01JC000000000000000000000B"
},
{
"product_id": "prd_01JC000000000000000000000C",
"for_person_id": "per_01JC000000000000000000000Z"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
items: [
{
product_id: "prd_01JC000000000000000000000A",
},
{
product_id: "prd_01JC000000000000000000000B",
},
{
product_id: "prd_01JC000000000000000000000C",
for_person_id: "per_01JC000000000000000000000Z",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/shopping.item.add_many HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"items": [
{
"product_id": "prd_01JC000000000000000000000A"
},
{
"product_id": "prd_01JC000000000000000000000B"
},
{
"product_id": "prd_01JC000000000000000000000C",
"for_person_id": "per_01JC000000000000000000000Z"
}
]
}HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R05C4ZFF27BGXXNAM7
{
"error": {
"code": "person_not_found",
"message": "Item 3: That person isn't in the household any more. No changes were applied.",
"details": {
"person_id": "per_01JC000000000000000000000Z",
"index": 2
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R05C4ZFF27BGXXNAM7"
}
}Put several things on the list at once
Added in order as one change. If one is refused, none are.
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/shopping.item.add_many' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01M6V9CT7N2YY2GJBBPVD2ZD2H' \
-d '{
"items": [
{
"product_name": "Baby spinach",
"quantity": 1,
"unit": "bag",
"recipe_id": "rcp_01M6V9CSD8VZYF11AC568Y7QPZ"
},
{
"product_name": "White beans",
"quantity": 2,
"unit": "can",
"recipe_id": "rcp_01M6V9CSD8VZYF11AC568Y7QPZ"
},
{
"product_name": "Vegetable broth",
"quantity": 1,
"unit": "carton",
"recipe_id": "rcp_01M6V9CSD8VZYF11AC568Y7QPZ"
},
{
"product_id": "prd_01M6V9CSWCK03ABGA7BSJA03Q1",
"quantity": 1,
"unit": "package",
"note": "A 4-pack. The filter is due soon."
},
{
"product_name": "Birthday candles"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/shopping.item.add_many", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01M6V9CT7N2YY2GJBBPVD2ZD2H",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
items: [
{
product_name: "Baby spinach",
quantity: 1,
unit: "bag",
recipe_id: "rcp_01M6V9CSD8VZYF11AC568Y7QPZ",
},
{
product_name: "White beans",
quantity: 2,
unit: "can",
recipe_id: "rcp_01M6V9CSD8VZYF11AC568Y7QPZ",
},
{
product_name: "Vegetable broth",
quantity: 1,
unit: "carton",
recipe_id: "rcp_01M6V9CSD8VZYF11AC568Y7QPZ",
},
{
product_id: "prd_01M6V9CSWCK03ABGA7BSJA03Q1",
quantity: 1,
unit: "package",
note: "A 4-pack. The filter is due soon.",
},
{
product_name: "Birthday candles",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/shopping.item.add_many HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01M6V9CT7N2YY2GJBBPVD2ZD2H
{
"items": [
{
"product_name": "Baby spinach",
"quantity": 1,
"unit": "bag",
"recipe_id": "rcp_01M6V9CSD8VZYF11AC568Y7QPZ"
},
{
"product_name": "White beans",
"quantity": 2,
"unit": "can",
"recipe_id": "rcp_01M6V9CSD8VZYF11AC568Y7QPZ"
},
{
"product_name": "Vegetable broth",
"quantity": 1,
"unit": "carton",
"recipe_id": "rcp_01M6V9CSD8VZYF11AC568Y7QPZ"
},
{
"product_id": "prd_01M6V9CSWCK03ABGA7BSJA03Q1",
"quantity": 1,
"unit": "package",
"note": "A 4-pack. The filter is due soon."
},
{
"product_name": "Birthday candles"
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CT7N12CRDXA3RGFEZE6Z
{
"result": {
"items": [
{
"item_id": "shi_01M6V9CT7NDTGH8Q6235X75TRQ",
"product_id": "prd_01M6V9CT7NYAYFKM62G2MNMNYY",
"merged": false
},
{
"item_id": "shi_01M6V9CT7NJAFAZA624X5HJFE7",
"product_id": "prd_01M6V9CT7NQ4N22J62H1W345SA",
"merged": false
},
{
"item_id": "shi_01M6V9CT7NV33ZA862550Z1QRH",
"product_id": "prd_01M6V9CT7NMP3FQ56224YCHPFJ",
"merged": false
},
{
"item_id": "shi_01M6V9CT7NNVHTKA72V67H9E98",
"product_id": "prd_01M6V9CSWCK03ABGA7BSJA03Q1",
"merged": false
},
{
"item_id": "shi_01M6V9CT7N0J83HDD19351XCXM",
"product_id": "prd_01M6V9CT7N753M4GD1C67KDDS1",
"merged": false
}
]
},
"version": 278
}For Rigel#
Rigel's tool for this command is shopping_item_add_many. Rigel runs this on its own, then says what it did. The agent guide has the rest.