Record a quote or an invoice
maintenance.invoice.record
POST/api/v1/households/{household_id}/commands/maintenance.invoice.record
- Command
- Rigel runs it
- Applies offline
Records a quote or an invoice as the paper gives it: who, for which visit or project, the dates, the amounts and its lines. Amounts are minor units of currency (required). file_id is the original paper, already uploaded. Without property_id, the property comes from the linked visit, project or line items. Everything linked must be at the same property (different_property). Recording an amount doesn't mean it was paid.
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 |
|---|---|
property_idstringoptional | Which property. Leave it out when the household has one property (it's made on first use); with several, give it, or the command is rejected with property_required. |
kindone of: quote, invoicerequired | quote (an estimate of work) or invoice (a bill for work done). |
file_idstringoptional | The original paper, already uploaded. |
contractor_idstringoptional | Who issued it. |
visit_idstringoptional | The visit it is for. |
project_idstringoptional | The project it is for. |
numberstringoptional | The invoice or quote number as printed. |
issued_onstring (date)optional | The date on the paper. |
service_onstring (date)optional | The day the work was done or is quoted for. |
currencystringrequired | An ISO 4217 currency code, such as USD. |
subtotalintegeroptional | The amount before tax, in minor units. |
taxintegeroptional | The tax, in minor units. |
totalintegeroptional | The total as the paper gives it, in minor units. Recording it doesn't mean it was paid. |
notesstringoptional | Anything else worth keeping, such as payment terms. |
linesarray of objectsoptional | The paper's line items, in order. |
lines[].descriptionstringrequired | What the line is for, as the paper words it. |
lines[].kindone of: labor, part, fee, tax, discount, otheroptional | labor, part, fee, tax, discount or other. Defaults to other. |
lines[].quantitynumberoptional | How many, or how many hours. |
lines[].unit_priceintegeroptional | The price of one, in minor units. |
lines[].amountintegeroptional | The line's total in minor units; negative for a discount. |
lines[].asset_idstringoptional | The item this line is for. |
Response#
200 The command was applied.
| Field | Description |
|---|---|
resultobjectrequired | What the command returned, such as the IDs it created. |
result.invoice_idstringrequired | The new quote or invoice. |
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 | file_not_found | A file that isn't there. |
404 | contractor_not_found | A contractor that isn't there. |
404 | visit_not_found | A visit that isn't there. |
404 | not_found | The household doesn't exist, or you aren't a member of it. |
409 | different_property |
|
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.
An invoice with its lines
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"kind": "invoice",
"file_id": "fil_01JC00000000000000000000F1",
"contractor_id": "ctr_01JC00000000000000000000K1",
"visit_id": "vst_01JC00000000000000000000V1",
"project_id": "mpj_01JC00000000000000000000J1",
"number": "INV-1042",
"issued_on": "2025-11-04",
"service_on": "2025-11-03",
"currency": "USD",
"subtotal": 40000,
"tax": 3300,
"total": 43300,
"notes": "Net 30",
"lines": [
{
"description": "Labor, 2 hours",
"kind": "labor",
"quantity": 2,
"unit_price": 12500,
"amount": 25000,
"asset_id": "ast_01JC00000000000000000000A1"
},
{
"description": "Igniter",
"kind": "part",
"amount": 15000
},
{
"description": "Fee"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
kind: "invoice",
file_id: "fil_01JC00000000000000000000F1",
contractor_id: "ctr_01JC00000000000000000000K1",
visit_id: "vst_01JC00000000000000000000V1",
project_id: "mpj_01JC00000000000000000000J1",
number: "INV-1042",
issued_on: "2025-11-04",
service_on: "2025-11-03",
currency: "USD",
subtotal: 40000,
tax: 3300,
total: 43300,
notes: "Net 30",
lines: [
{
description: "Labor, 2 hours",
kind: "labor",
quantity: 2,
unit_price: 12500,
amount: 25000,
asset_id: "ast_01JC00000000000000000000A1",
},
{
description: "Igniter",
kind: "part",
amount: 15000,
},
{
description: "Fee",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"kind": "invoice",
"file_id": "fil_01JC00000000000000000000F1",
"contractor_id": "ctr_01JC00000000000000000000K1",
"visit_id": "vst_01JC00000000000000000000V1",
"project_id": "mpj_01JC00000000000000000000J1",
"number": "INV-1042",
"issued_on": "2025-11-04",
"service_on": "2025-11-03",
"currency": "USD",
"subtotal": 40000,
"tax": 3300,
"total": 43300,
"notes": "Net 30",
"lines": [
{
"description": "Labor, 2 hours",
"kind": "labor",
"quantity": 2,
"unit_price": 12500,
"amount": 25000,
"asset_id": "ast_01JC00000000000000000000A1"
},
{
"description": "Igniter",
"kind": "part",
"amount": 15000
},
{
"description": "Fee"
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R084XC5DFBGR4FY7DF
{
"result": {
"invoice_id": "ivc_01JC4N0000MBGE5RJ6Q7V6V6T8"
},
"version": 1
}A bare quote makes the property on first use
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"kind": "quote",
"currency": "USD",
"total": 120000
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
kind: "quote",
currency: "USD",
total: 120000,
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"kind": "quote",
"currency": "USD",
"total": 120000
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0Y0N09AYNQ3KSENWS
{
"result": {
"invoice_id": "ivc_01JC4N0000JVP6PWJ6S8P7WZ6B"
},
"version": 1
}The property comes from the visit when there are several
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"kind": "invoice",
"currency": "USD",
"visit_id": "vst_01JC00000000000000000000V1"
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
kind: "invoice",
currency: "USD",
visit_id: "vst_01JC00000000000000000000V1",
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"kind": "invoice",
"currency": "USD",
"visit_id": "vst_01JC00000000000000000000V1"
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0TPN044VR8TQSN2WQ
{
"result": {
"invoice_id": "ivc_01JC4N0000MBGE5RJ6Q7V6V6T8"
},
"version": 1
}A visit at another property
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"visit_id": "vst_01JC00000000000000000000V1"
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
property_id: "prp_01JC00000000000000000000P1",
kind: "invoice",
currency: "USD",
visit_id: "vst_01JC00000000000000000000V1",
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"visit_id": "vst_01JC00000000000000000000V1"
}HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0GMTXYWEM4VP0PQ3K
{
"error": {
"code": "different_property",
"message": "That visit is at a different property. No changes were applied.",
"details": {
"property_id": "prp_01JC00000000000000000000P2"
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R0GMTXYWEM4VP0PQ3K"
}
}A project at another property
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"project_id": "mpj_01JC00000000000000000000J1"
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
property_id: "prp_01JC00000000000000000000P1",
kind: "invoice",
currency: "USD",
project_id: "mpj_01JC00000000000000000000J1",
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"project_id": "mpj_01JC00000000000000000000J1"
}HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0SJGF9JYM6910HWKE
{
"error": {
"code": "different_property",
"message": "That project is at a different property. No changes were applied.",
"details": {
"property_id": "prp_01JC00000000000000000000P2"
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R0SJGF9JYM6910HWKE"
}
}A line's item at another property
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"lines": [
{
"description": "x",
"asset_id": "ast_01JC00000000000000000000A2"
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
property_id: "prp_01JC00000000000000000000P1",
kind: "invoice",
currency: "USD",
lines: [
{
description: "x",
asset_id: "ast_01JC00000000000000000000A2",
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"lines": [
{
"description": "x",
"asset_id": "ast_01JC00000000000000000000A2"
}
]
}HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0XPHXE60477RT28J3
{
"error": {
"code": "different_property",
"message": "That item is at a different property. No changes were applied.",
"details": {
"property_id": "prp_01JC00000000000000000000P2"
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R0XPHXE60477RT28J3"
}
}A file that isn't there
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"file_id": "fil_01JC00000000000000000000F1"
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
property_id: "prp_01JC00000000000000000000P1",
kind: "invoice",
currency: "USD",
file_id: "fil_01JC00000000000000000000F1",
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"file_id": "fil_01JC00000000000000000000F1"
}HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0NDE531R1V84XWV8K
{
"error": {
"code": "file_not_found",
"message": "That file isn't there any more. No changes were applied.",
"details": {
"file_id": "fil_01JC00000000000000000000F1"
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R0NDE531R1V84XWV8K"
}
}A contractor that isn't there
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"contractor_id": "ctr_01JC00000000000000000000K1"
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
property_id: "prp_01JC00000000000000000000P1",
kind: "invoice",
currency: "USD",
contractor_id: "ctr_01JC00000000000000000000K1",
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"contractor_id": "ctr_01JC00000000000000000000K1"
}HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0ASHZV0T013BA5G1W
{
"error": {
"code": "contractor_not_found",
"message": "That contractor isn't there any more. No changes were applied.",
"details": {
"contractor_id": "ctr_01JC00000000000000000000K1"
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R0ASHZV0T013BA5G1W"
}
}A visit that isn't there
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
-d '{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"visit_id": "vst_01JC00000000000000000000V1"
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
property_id: "prp_01JC00000000000000000000P1",
kind: "invoice",
currency: "USD",
visit_id: "vst_01JC00000000000000000000V1",
}),
});
const data = await response.json();POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA
{
"property_id": "prp_01JC00000000000000000000P1",
"kind": "invoice",
"currency": "USD",
"visit_id": "vst_01JC00000000000000000000V1"
}HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0C4J634S38D6CE8CW
{
"error": {
"code": "visit_not_found",
"message": "That visit isn't there any more. No changes were applied.",
"details": {
"visit_id": "vst_01JC00000000000000000000V1"
},
"recovery": "Read the current state, then send a command that fits it.",
"request_id": "req_01K9D9S2R0C4J634S38D6CE8CW"
}
}Record an invoice for a visit
Amounts are in minor units of the currency. Recording one doesn't mean it was paid.
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01M6V9CSYRENCW404YAB9T65ZM' \
-d '{
"kind": "invoice",
"contractor_id": "ctr_01M6V9CSWHPNYAY4A5FBX3R14F",
"visit_id": "vst_01M6V9CSYM7MF5MW4XZSAPDX0R",
"number": "RB-3071",
"issued_on": "2026-09-18",
"service_on": "2026-09-18",
"currency": "USD",
"subtotal": 14500,
"tax": 0,
"total": 14500,
"notes": "Paid by card at the visit.",
"lines": [
{
"description": "Trip fee",
"kind": "fee",
"amount": 9500
},
{
"description": "Supply line washer and labor",
"kind": "labor",
"amount": 5000
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01M6V9CSYRENCW404YAB9T65ZM",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
kind: "invoice",
contractor_id: "ctr_01M6V9CSWHPNYAY4A5FBX3R14F",
visit_id: "vst_01M6V9CSYM7MF5MW4XZSAPDX0R",
number: "RB-3071",
issued_on: "2026-09-18",
service_on: "2026-09-18",
currency: "USD",
subtotal: 14500,
tax: 0,
total: 14500,
notes: "Paid by card at the visit.",
lines: [
{
description: "Trip fee",
kind: "fee",
amount: 9500,
},
{
description: "Supply line washer and labor",
kind: "labor",
amount: 5000,
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01M6V9CSYRENCW404YAB9T65ZM
{
"kind": "invoice",
"contractor_id": "ctr_01M6V9CSWHPNYAY4A5FBX3R14F",
"visit_id": "vst_01M6V9CSYM7MF5MW4XZSAPDX0R",
"number": "RB-3071",
"issued_on": "2026-09-18",
"service_on": "2026-09-18",
"currency": "USD",
"subtotal": 14500,
"tax": 0,
"total": 14500,
"notes": "Paid by card at the visit.",
"lines": [
{
"description": "Trip fee",
"kind": "fee",
"amount": 9500
},
{
"description": "Supply line washer and labor",
"kind": "labor",
"amount": 5000
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CSYRWZCG5X2RBN5HWABV
{
"result": {
"invoice_id": "ivc_01M6V9CSYRAE8F77HCCX98XB0M"
},
"version": 217
}Record a quote for a project
A quote is kept apart from invoices when the project adds them up.
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/maintenance.invoice.record' \
-H "Cookie: rigel_session=$RIGEL_SESSION" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cmd_01M6V9CSZGZV9A5PK0RQG291CA' \
-d '{
"kind": "quote",
"contractor_id": "ctr_01M6V9CSWHPNYAY4A5FBX3R14F",
"project_id": "mpj_01M6V9CSZC4PE99PPRAQ7ASEZQ",
"number": "Q-2290",
"issued_on": "2026-11-04",
"currency": "USD",
"subtotal": 118000,
"tax": 7000,
"total": 125000,
"lines": [
{
"description": "Window well drain and gravel",
"kind": "labor",
"amount": 89000
},
{
"description": "Sealant and flashing",
"kind": "part",
"amount": 29000
},
{
"description": "Sales tax",
"kind": "tax",
"amount": 7000
}
]
}'const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/maintenance.invoice.record", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "cmd_01M6V9CSZGZV9A5PK0RQG291CA",
Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
},
body: JSON.stringify({
kind: "quote",
contractor_id: "ctr_01M6V9CSWHPNYAY4A5FBX3R14F",
project_id: "mpj_01M6V9CSZC4PE99PPRAQ7ASEZQ",
number: "Q-2290",
issued_on: "2026-11-04",
currency: "USD",
subtotal: 118000,
tax: 7000,
total: 125000,
lines: [
{
description: "Window well drain and gravel",
kind: "labor",
amount: 89000,
},
{
description: "Sealant and flashing",
kind: "part",
amount: 29000,
},
{
description: "Sales tax",
kind: "tax",
amount: 7000,
},
],
}),
});
const data = await response.json();POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/maintenance.invoice.record HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01M6V9CSZGZV9A5PK0RQG291CA
{
"kind": "quote",
"contractor_id": "ctr_01M6V9CSWHPNYAY4A5FBX3R14F",
"project_id": "mpj_01M6V9CSZC4PE99PPRAQ7ASEZQ",
"number": "Q-2290",
"issued_on": "2026-11-04",
"currency": "USD",
"subtotal": 118000,
"tax": 7000,
"total": 125000,
"lines": [
{
"description": "Window well drain and gravel",
"kind": "labor",
"amount": 89000
},
{
"description": "Sealant and flashing",
"kind": "part",
"amount": 29000
},
{
"description": "Sales tax",
"kind": "tax",
"amount": 7000
}
]
}HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CSZGD28PV8DC4Z4E5J5M
{
"result": {
"invoice_id": "ivc_01M6V9CSZG00MBBMM5BA15SCMT"
},
"version": 223
}For Rigel#
Rigel's tool for this command is maintenance_invoice_record. Rigel runs this on its own, then says what it did. The agent guide has the rest.