Skip to content

Complete task

POST
/v1/actions/hospitality.action.complete_housekeeping_task/apply
curl --request POST \
--url https://api.aerandil.com/v1/actions/hospitality.action.complete_housekeeping_task/apply \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "branch": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "params": { "completed_at": "2026-04-15T12:00:00Z", "consumed": [ { "material_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "quantity": "example" } ], "expected_holder_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "inspection_outcome": "passed", "inspection_rating": 1, "notes": "example", "resulting_status": "dirty", "self_rating": 1, "stay_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }, "return_modified": false, "target": { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "object_type": "hospitality.housekeeping_task" } }'

Mark a housekeeping task complete and update the room’s status. Without resulting_status, only the unambiguous cascade runs: a departure / vacant_pickup / deep_clean / inspection completed against a dirty or pickup room promotes the cleaning axis to clean, and a stayover / turndown leaves it alone. With resulting_status, the attendant states the room’s cleaning status at Finish (OPERA’s Companion sets it at the same tap) and it is written in the same transaction, through the same refusal the status report applies: a room under an active out-of-order block today cannot have its cleaning status written — return_room_to_service decides. When the most specific active checklist template for the task’s type and room type is required_for_completion, the task refuses to complete until a result for it is recorded (record_checklist_result). On an inspection task, inspection_rating (1–5) and inspection_outcome record the supervisor’s verdict on the inspection and on the cleaning it rated — the most recent completed non-inspection task for the same room and business date, linked by inspection_rates_task (refused when there is none) — and a failed outcome mints a high-priority re-clean of the same type (origin reclean), linked by housekeeping_task_from_inspection. Without resulting_status, a passed inspection leaves the room inspected and a failed one dirty. A cleaning never needs an inspection to count. A runner’s session may not state the room — neither resulting_status nor an inspection’s verdict — and is refused (403): a room’s condition is the word of the attendant who cleaned it and the supervisor who inspected it; a runner’s finish leaves the room to the type-based cascade. A public area’s task (2026-10-14) has no room to state: resulting_status is refused on it, and a public_area_inspection’s verdict rates the area’s latest completed clean of the day and re-mints a failed one for the area, as a room’s inspection does. A minibar or laundry task (2026-10-14) may carry what it consumed — catalogued materials and quantities. A minibar’s are minibar products, consumed from the room’s own minibar store or the house’s default minibar cart and charged at their sale price (the house’s minibar tax rules derived) through post_charge to the bill of the stay that was in the room at completed_at — when the minibar was checked, not when a queued finish lands (2026-10-17) — while it is in house; with nobody in house to charge (the room empty at the check, or its guest gone since) the stock is still consumed, uncharged, and minibar.uncharged.recorded hands the desk its late charge, naming that stay or the last to leave by the check, never a guest who arrived after it; in a shared room stay_id names whose bill (in house, and arrived by the check). A laundry’s are issued from the house’s default laundry store to the room. Any other task type refuses consumed. self_rating (2026-10-15, 1–5) is the attendant’s own rating of the work, stored on the task beside — never instead of — the supervisor’s inspection_rating; it states nothing about the room, so a runner may send it; refused on an inspection. A finish is the holder’s (2026-10-17): an attendant, runner or engineer who does not hold a task a colleague holds is refused (403), while the housekeeping supervisor and the desk finish it on the holder’s behalf; a task nobody holds, or a worker group’s, is taken by the staff member who finishes it, as a start takes it (a non-member is refused, 403). self_rating is the holder’s own word, refused (403) to anyone else — the supervisor, the desk, an agent. expected_holder_id names the holder the caller saw (a finish queued on a handset): refused (422) when someone else, a group or nobody holds the task by the time it lands.

Effects: modify hospitality.housekeeping_task; modify hospitality.room; link hospitality.link.inspection_rates_task; link hospitality.link.housekeeping_task_from_inspection; create hospitality.housekeeping_task; link hospitality.link.housekeeping_task_for_room; link hospitality.link.housekeeping_task_from_triage; link hospitality.link.housekeeping_task_assigned_to; unlink hospitality.link.housekeeping_task_assigned_to_group; link hospitality.link.housekeeping_task_for_area; link hospitality.link.housekeeping_task_requested_by_stay; create hospitality.stock_movement; create hospitality.stock_level; modify hospitality.stock_level; link hospitality.link.stock_movement_for_level; link hospitality.link.stock_level_for_material; link hospitality.link.stock_level_in_store; link hospitality.link.stock_movement_recorded_by; link hospitality.link.stock_movement_for_housekeeping_task; link hospitality.link.stock_movement_for_room; create hospitality.charge; create hospitality.tax_application; link hospitality.link.folio_has_charge; link hospitality.link.charge_has_tax_application; link hospitality.link.charge_for_service_item; link hospitality.link.charge_at_outlet; modify hospitality.folio.

Media typeapplication/json
object
branch

Apply against an open branch’s overlay view instead of the canonical (main) plane. The action’s writes land in the branch’s copy-on-first-write overlay, its events in the branch’s own stream, and the invocation is journaled for merge-by-replay. Branch writes are action-only, so this is the write-side entry point to a branch (POST /v1/branches forks one).

string format: uuid
params
required
object
completed_at
required
Completed at
string format: date-time
consumed
Consumption
Array<object>
object
material_id
required
string format: uuid
quantity
required
string format: decimal
expected_holder_id
Who the caller saw holding it — refused when that has changed
string format: uuid
inspection_outcome
passed, or failed (re-opens the cleaning) — inspection tasks only
string
Allowed values: passed failed
inspection_rating
Inspection score, 1 (poor) to 5 (excellent) — inspection tasks only
integer
notes
Notes
string
resulting_status
Cleaning status the room is left in (defaults to the type-based cascade)
string
Allowed values: dirty pickup clean inspected
self_rating
The attendant's own rating of the work, 1 (poor) to 5 (excellent) — not on an inspection
integer
stay_id
The in-house stay whose bill takes a minibar charge (a shared room only)
string format: uuid
return_modified

When true, the response carries modified_objects and modified_links projections — the engine reads the event log inside the same transaction so the projection observes the handler’s own writes.

boolean
target
required
object
id
required
string format: uuid
object_type
required
Allowed value: hospitality.housekeeping_task

Action applied. modified_objects and modified_links populated when return_modified: true was supplied.

Media typeapplication/json
ApplyActionResponse

Envelope returned by the Aerandil action engine. correlation_id ties every event emitted by this invocation; modified_objects and modified_links project the events the handler emitted (per the action’s declared effects); warnings carries any non-blocking soft-validator observations.

object
correlation_id
required

Per-invocation correlation id; matches events.correlation_id for every event this action appended.

string format: uuid
modified_links
required

Links established or removed by this invocation. Empty when the caller did not request return_modified.

Array<object>
object
from_id
required
string format: uuid
from_type
required
string
kind
required
Allowed values: linked unlinked end_dated
link_type
required
Allowed values: hospitality.link.inspection_rates_task hospitality.link.housekeeping_task_from_inspection hospitality.link.housekeeping_task_for_room hospitality.link.housekeeping_task_from_triage hospitality.link.housekeeping_task_assigned_to hospitality.link.housekeeping_task_assigned_to_group hospitality.link.housekeeping_task_for_area hospitality.link.housekeeping_task_requested_by_stay hospitality.link.stock_movement_for_level hospitality.link.stock_level_for_material hospitality.link.stock_level_in_store hospitality.link.stock_movement_recorded_by hospitality.link.stock_movement_for_housekeeping_task hospitality.link.stock_movement_for_room hospitality.link.folio_has_charge hospitality.link.charge_has_tax_application hospitality.link.charge_for_service_item hospitality.link.charge_at_outlet
to_id
required
string format: uuid
to_type
required
string
modified_objects
required

Objects created, modified, or soft-deleted by this invocation. Empty when the caller did not request return_modified.

Array<object>
object
id
required
string format: uuid
kind
required
Allowed values: modified created
object_type
required
Allowed values: hospitality.housekeeping_task hospitality.room hospitality.stock_movement hospitality.stock_level hospitality.charge hospitality.tax_application hospitality.folio
warnings

Non-blocking soft-validator observations emitted during this invocation (e.g. comp-authority over-limit, recipe pour-cost over sell-price). Absent when no warnings were emitted.

Array<object>
object
message
required

Human-readable summary, suitable for logging or operator-UI surfacing.

string
object_type
required

Object type the warning was raised against.

string
property

Property the warning anchors to, when a single field is the locus. Absent for multi-field rules.

string
rule
required

Stable kebab-case rule identifier (e.g. comp-authority-over-limit).

string
Example
{
"modified_links": [
{
"kind": "linked",
"link_type": "hospitality.link.inspection_rates_task"
}
],
"modified_objects": [
{
"kind": "modified",
"object_type": "hospitality.housekeeping_task"
}
]
}

Conflict — concurrent modification or unique constraint violation.

Validation error — parameter validation or business-rule violation.